library(data.table)
data.table 1.14.0 using 1 threads (see ?getDTthreads).  Latest news: r-datatable.com
**********
This installation of data.table has not detected OpenMP support. It should still work but in single-threaded mode.
This is a Mac. Please read https://mac.r-project.org/openmp/. Please engage with Apple and ask them for support. Check r-datatable.com for updates, and our Mac instructions here: https://github.com/Rdatatable/data.table/wiki/Installation. After several years of many reports of installation problems on Mac, it's time to gingerly point out that there have been no similar problems on Windows or Linux.
**********

Attaching package: ‘data.table’

The following object is masked _by_ ‘.GlobalEnv’:

    .N
library(readxl)
library(ggrepel)
Loading required package: ggplot2
library(ggplot2)
library(cowplot)
library(DescTools)

Attaching package: ‘DescTools’

The following objects are masked from ‘package:Hmisc’:

    %nin%, Label, Mean, Quantile

The following object is masked from ‘package:data.table’:

    %like%
library(stringr)
library(ggplot2)
library(data.table)
library(readr)
library(Hmisc)
library(cowplot)
func_annotation <- data.table(read_excel("/Users/gp7/Google_Drive/Results/Non_B/potassium_experiments/DGA/13059_2020_1982_MOESM2_ESM.xlsx"))


vulcano.spliceosome <- ggplot() +
geom_point(data = human_diff[!is.na(Gene)], aes( -log2FoldChange, -log10(padj)  ), colour="grey", alpha=0.5  )+
  geom_point(data = human_diff[padj<0.05 &  Spliceosome==1 , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="orange", alpha=0.8   ) +
geom_point(data = human_diff[padj<0.05 & abs(log2FoldChange)>=0.5 &  Spliceosome==1 , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="red", alpha=0.8   ) +
geom_text_repel(data = human_diff[padj<0.05 & Spliceosome==1 , ],
                colour="black", aes( -log2FoldChange, -log10(padj),
                label=human_diff[padj<0.05 &  Spliceosome==1 , Gene]),
                force = 1.5
                #nudge_x      = 0.3
                #direction    = "x",
                #angle        = 90,
                #vjust        = 1,
                #segment.size = 1,
                #label.size = 0.05,
                )   +  
xlim(c(-1,1)) +
xlab(expression(log[2]~Fold~Change))+
ylab(expression (-log[10]~"Adjusted p-value"))+
theme_bw()


vulcano.factors <- ggplot() +
geom_point(data = human_diff[!is.na(Gene)], aes( -log2FoldChange, -log10(padj)  ), colour="grey", alpha=0.5  )+
geom_point(data = human_diff[padj<0.05 & (`Splicing regulation`==1 & Spliceosome==0)  , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="orange", alpha=0.8   ) +  
geom_point(data = human_diff[padj<0.05 & abs(log2FoldChange)>=0.5 & (`Splicing regulation`==1 & Spliceosome==0) , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="red", alpha=0.8   ) +
geom_text_repel(data = human_diff[padj<0.05 & (`Splicing regulation`==1 & Spliceosome==0)  , ],
                colour="black", aes( -log2FoldChange, -log10(padj),
                label=human_diff[padj<0.05 & (`Splicing regulation`==1 & Spliceosome==0)   , Gene]),
                force = 1.5,
                max.overlaps = Inf,
                #nudge_x      = 0.3
                #direction    = "x",
                #angle        = 90,
                #vjust        = 1,
                #segment.size = 1,
                #label.size = 0.05,
                )   +  
xlim(c(-1,1)) +
xlab(expression(log[2]~Fold~Change))+
ylab(expression (-log[10]~"Adjusted p-value"))+
theme_bw()

vulcano.helicase <- ggplot() +
geom_point(data = human_diff[!is.na(Gene)], aes( -log2FoldChange, -log10(padj)  ), colour="grey", alpha=0.5  )+
  geom_point(data = human_diff[padj<0.05  &  (Helicase==1) , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="orange", alpha=0.8   ) +
geom_point(data = human_diff[padj<0.05 &  abs(log2FoldChange)>=0.5 &  (Helicase==1) , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="red", alpha=0.8   ) +
geom_text_repel(data = human_diff[padj<0.05 & (Helicase==1) , ],
                colour="black", aes( -log2FoldChange, -log10(padj),
                label=human_diff[padj<0.05 & (Helicase==1)  , Gene]),
                force = 1.5
                #nudge_x      = 0.3
                #direction    = "x",
                #angle        = 90,
                #vjust        = 1,
                #segment.size = 1,
                #label.size = 0.05,
                )   +  
xlim(c(-1,1)) +
xlab(expression(log[2]~Fold~Change))+
ylab(expression (-log[10]~"Adjusted p-value"))+
theme_bw()
vulcano.factors <- ggplot() +
geom_point(data = human_diff[!is.na(Gene)], aes( -log2FoldChange, -log10(padj)  ), colour="grey", alpha=0.5  )+
geom_point(data = human_diff[padj<0.05 & (`Splicing regulation`==1 & Spliceosome==0)  , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="orange", alpha=0.8   ) +  
geom_point(data = human_diff[padj<0.05 & abs(log2FoldChange)>=0.5 & (`Splicing regulation`==1 & Spliceosome==0) , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="red", alpha=0.8   ) +
geom_text_repel(data = human_diff[padj<0.05 & (`Splicing regulation`==1 & Spliceosome==0) & abs(log2FoldChange)>=0.5  , ],
                colour="black", aes( -log2FoldChange, -log10(padj),
                label=human_diff[padj<0.05 & (`Splicing regulation`==1 & Spliceosome==0) & abs(log2FoldChange)>=0.5 &  , Gene]),
                force = 1.5
                #nudge_x      = 0.3
                #direction    = "x",
                #angle        = 90,
                #vjust        = 1,
                #segment.size = 1,
                #label.size = 0.05,
                )   +  
xlim(c(-1,1)) +
xlab(expression(log[2]~Fold~Change))+
ylab(expression (log[10]~"Adjusted p-value"))+
theme_bw()

ggplot() +
geom_point(data = human_diff, aes( -log2FoldChange, -log10(padj)  ), colour="grey", alpha=0.5  )+
geom_point(data = human_diff[  padj<0.05 & abs(log2FoldChange)>=0.5 , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="red", alpha=0.8   ) +

xlab(expression(log[2]~Fold~Change))+
ylab(expression (log[10]~"Adjusted p-value"))+
theme_bw()

ggplot() +
geom_point(data = human_diff[!is.na(Gene)], aes( -log2FoldChange, -log10(padj)  ), colour="grey", alpha=0.5  )+
geom_point(data = human_diff[(Gene %in% filtered_factors.KCL) & padj<0.05 & abs(log2FoldChange)>=0.5 , ], aes( -log2FoldChange, -log10(padj) ) ,  colour="red", alpha=0.8   ) +
geom_text_repel(data = human_diff[(Gene %in% filtered_factors.KCL) & padj<0.05 & abs(log2FoldChange)>=0.5 , ],
                colour="black", aes( -log2FoldChange, -log10(padj),
                label=human_diff[(Gene %in% filtered_factors.KCL) & padj<0.05 & abs(log2FoldChange)>=0.5  , Gene]),
                force = 1.5
                #nudge_x      = 0.3
                #direction    = "x",
                #angle        = 90,
                #vjust        = 1,
                #segment.size = 1,
                #label.size = 0.05,
                )   +  
xlim(c(-1,1)) +
xlab(expression(log[2]~Fold~Change))+
ylab(expression (log[10]~"Adjusted p-value"))+
theme_bw()

plot_grid(vulcano.spliceosome, vulcano.factors, labels = "AUTO", rows = 1)
Argument 'rows' is deprecated. Use 'nrow' instead.Removed 1 rows containing missing values (geom_point).Removed 1 rows containing missing values (geom_point).

human_diff[padj<0.05 & !is.na(Gene),][order(-abs(log2FoldChange)]
Error: unexpected ']' in "human_diff[padj<0.05 & !is.na(Gene),][order(-abs(log2FoldChange)]"

Experimental transition figure

matrix.total.delta_sums
     Non_template    Template                             ID     Factor_ID  Cell        File    Gene Specie
  1:   -12.665789    0.000000   DKC1-human_HepG2_ENCFF002FLD    DKC1-human HepG2 ENCFF002FLD    DKC1  human
  2:    -1.885892  -17.905991 ZC3H11A-human_K562_ENCFF002MQE ZC3H11A-human  K562 ENCFF002MQE ZC3H11A  human
  3:     9.598246    4.483051   TRA2A-human_K562_ENCFF004IIT   TRA2A-human  K562 ENCFF004IIT   TRA2A  human
  4:   -43.993417  -43.242167    GNL3-human_K562_ENCFF004XHQ    GNL3-human  K562 ENCFF004XHQ    GNL3  human
  5:   -81.019901 -107.607471   DDX24-human_K562_ENCFF006KFT   DDX24-human  K562 ENCFF006KFT   DDX24  human
 ---                                                                                                       
673:   -37.115446  -48.539389  RBM22-human_HepG2_ENCFF990UNN   RBM22-human HepG2 ENCFF990UNN   RBM22  human
674:     3.220706  -20.249391    WDR3-human_K562_ENCFF991NPH    WDR3-human  K562 ENCFF991NPH    WDR3  human
675:   -10.271694  114.959928 HNRNPK-human_HepG2_ENCFF993NVI  HNRNPK-human HepG2 ENCFF993NVI  HNRNPK  human
676:     6.942830  -26.615233  FKBP4-human_HepG2_ENCFF993XGD   FKBP4-human HepG2 ENCFF993XGD   FKBP4  human
677:   -16.982291  -62.103603  RBFOX2-human_K562_ENCFF994PFX  RBFOX2-human  K562 ENCFF994PFX  RBFOX2  human

ggplot() +
geom_point(data = matrix.total.delta_sums.kcl[!is.na(Gene)], aes( Non_template.mean, Template.mean  ), colour="grey", alpha=0.5  )+
geom_point(data = matrix.total.delta_sums.kcl[padj<0.05 & log2FoldChange<0 & (`Helicase`==1) , ], aes( Non_template.mean, Template.mean  ) ,  colour="red", alpha=0.8   ) +
geom_point(data = matrix.total.delta_sums.kcl[padj<0.05 & log2FoldChange>0 &  (`Helicase`==1 ) , ], aes( Non_template.mean, Template.mean ) ,  colour="blue", alpha=0.8   ) +  
  
geom_text_repel(data = matrix.total.delta_sums.kcl[padj<0.05 & (`Helicase`==1 ) , ],
                colour="black", aes( Non_template.mean, Template.mean,
                label=matrix.total.delta_sums.kcl[padj<0.05 & (`Helicase`==1 )  , Gene]),
                force = 1.5
                #nudge_x      = 0.3
                #direction    = "x",
                #angle        = 90,
                #vjust        = 1,
                #segment.size = 1,
                #label.size = 0.05,
                )   +
  
facet_grid(Cell ~ .) +
#xlim(c(-1,1)) +
xlab(expression(log[2]~Fold~Change))+
ylab(expression (log[10]~"Adjusted p-value"))+
theme_bw()

read_dist_table <- function(path){
  
dist_table <- data.table(read_delim(path, 
    "\t", escape_double = FALSE, col_names = FALSE, 
    trim_ws = TRUE))
dist_table <- dist_table[, 2:2001]
dist_table <- data.table(as.data.frame(t(dist_table)))
colnames(dist_table) <- c("Position", "Occurrences")
dist_table[,median:=median(Occurrences)]
dist_table[, Enrrichment:=Occurrences/median]
dist_table[, Position:=Position-1]
return(dist_table)  
}
plot_density_binomial_RBP <- function(up_plus, up_minus, down_plus, down_minus, observations_up, observations_down, sig){
  
  up_TOTAL <-  merge(up_plus, up_minus, by="Position")
  up_TOTAL[,Occurrences:=Occurrences.x+Occurrences.y]
  up_TOTAL[,Occurrences:=Occurrences.x+Occurrences.y]
  
  
  
  up_TOTAL <- cbind(up_TOTAL, up_TOTAL[, binconf(Occurrences, observations_up, alpha=sig) ])
  up_TOTAL[,median:=median(PointEst)]
  up_TOTAL[, Enrrichment:=PointEst/median]
  up_TOTAL[, Enrrichment_l:=Lower/median]
  up_TOTAL[, Enrrichment_u:=Upper/median]
  up_TOTAL[, Position:=Position-1]
  
  
  down_TOTAL <-  merge(down_plus, down_minus, by="Position")
  down_TOTAL[,Occurrences:=Occurrences.x+Occurrences.y]
  
  down_TOTAL <- cbind(down_TOTAL, down_TOTAL[, binconf(Occurrences, observations_down, alpha=sig) ])
  down_TOTAL[,median:=median(PointEst)]
  down_TOTAL[, Enrrichment:=PointEst/median]
  down_TOTAL[, Enrrichment_l:=Lower/median]
  down_TOTAL[, Enrrichment_u:=Upper/median]
  down_TOTAL[, Position:=Position-1]  
  
  
  up_TOTAL[ ,exon_pos:="Upstream"]
  down_TOTAL[ ,exon_pos:="Downstream"]
  
  TOTAL <- rbind(up_TOTAL, down_TOTAL)
  
  TOTAL$exon_pos <-  factor(TOTAL$exon_pos, levels=c("Upstream", "Downstream" )) 
  
  p <- ggplot(TOTAL)+
    geom_line(aes(x=Position,y=Enrrichment)) +
    geom_ribbon(aes(ymin=Enrrichment_l, ymax=Enrrichment_u, x=Position), alpha=0.3 )+
    facet_grid( . ~ exon_pos ) +
    theme_bw()
  
  #show(p)
  
  return(TOTAL) 
  
}
plot_eql_diff_binomial_table <- function(eql_up_plus, eql_up_minus, eql_down_plus, eql_down_minus, diff_up_plus, diff_up_minus, diff_down_plus, diff_down_minus, TOTAL.eql_up, TOTAL.eql_down, TOTAL.diff_up, TOTAL.diff_down, sig   ){ 
diff.up_plus <- read_dist_table(diff_up_plus)
diff.up_minus <- read_dist_table(diff_up_minus)
diff.down_plus <- read_dist_table(diff_down_plus)
diff.down_minus <- read_dist_table(diff_down_minus)
diff.up_minus[,Position:=Position*-1]
diff.down_minus[,Position:=Position*-1]
diff.TOTAL <- plot_density_binomial_RBP(diff.up_plus, diff.up_minus, diff.down_plus, diff.down_minus, TOTAL.diff_up, TOTAL.diff_down, sig)
eql.up_plus <- read_dist_table(eql_up_plus)
eql.up_minus <- read_dist_table(eql_up_minus)
eql.down_plus <- read_dist_table(eql_down_plus)
eql.down_minus <- read_dist_table(eql_down_minus)
eql.up_minus[,Position:=Position*-1]
eql.down_minus[,Position:=Position*-1]
eql.TOTAL <- plot_density_binomial_RBP(eql.up_plus, eql.up_minus, eql.down_plus, eql.down_minus, TOTAL.eql_up, TOTAL.eql_down, sig)
diff.TOTAL[, type:="wG4"]
eql.TOTAL[, type:="woG4"]
diff_eql.TOTAL <- rbind(diff.TOTAL, eql.TOTAL)
return(diff_eql.TOTAL)
}
files <- list.files("./RBPs/", pattern ="exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.")
samples <- str_replace(str_replace(files,  "exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.", "" ), ".bed.list.out.num", "")
metadata <- fread("./RBPs/metadata.tsv")
#sample = 'ENCFF786JAM'
figure6_samples <- c("ENCFF465QKS", "ENCFF404OSK", "ENCFF877KBJ", "ENCFF014BXV", "ENCFF639MYI")
figure6_samples
[1] "ENCFF465QKS" "ENCFF404OSK" "ENCFF877KBJ" "ENCFF014BXV" "ENCFF639MYI"
unique(figure6_table$ID)
[1] "ENCFF465QKS" "ENCFF404OSK" "ENCFF877KBJ" "ENCFF014BXV" "ENCFF639MYI"
figure6_samples %in% unique(figure6_table$ID)
[1] FALSE FALSE  TRUE  TRUE  TRUE
Rebuttal


figure6_table <- data.table()

for (sample in figure6_samples){
  
  if (length( list.files("./RBPs/", pattern = sample))>=16){

  RBP_binomial_table_non_template <- plot_eql_diff_binomial_table(
  paste("./RBPs/exon.up_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.up_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.up_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.up_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  110870 + 109467,
  108638 + 107433,
  3587 + 3431,
  5819 + 5465,
  0.05
  )
  
  RBP_binomial_table_non_template$pos_int <- cut(RBP_binomial_table_non_template$Position, breaks = 40, labels = seq(-999,1000,50)-1)
  RBP_binomial_table_non_template_stats <- RBP_binomial_table_non_template[ , .(Enrrichment=mean(Enrrichment), Enrrichment_l=mean(Enrrichment_l), Enrrichment_u=mean(Enrrichment_u))  , by=c( "exon_pos", "type",  "pos_int"  ) ]
  
  
  Total.Overlaps.non_template <- c()
  
  for (i in seq(-200, 200, 50)){
  
  O.Upstream <- Overlap(
  RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="wG4", c("Enrrichment_l", "Enrrichment_u")],
  RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="woG4", c("Enrrichment_l", "Enrrichment_u")]
  )
  
  O.Downstream <- Overlap(
  RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="wG4", c("Enrrichment_l", "Enrrichment_u")],
  RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="woG4", c("Enrrichment_l", "Enrrichment_u")]
  )
  
  Total.Overlaps.non_template <- rbind(Total.Overlaps.non_template, c(O.Upstream, O.Downstream))
  
  }
  
  
  RBP_binomial_table_template <- plot_eql_diff_binomial_table(
  paste("./RBPs/exon.up_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.up_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.up_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.up_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  110841 + 109504,
  111508 + 110025,
  3616 + 3394,
  2949 + 2873,
  0.05
  )
  
  
  
  RBP_binomial_table_template$pos_int <- cut(RBP_binomial_table_template$Position, breaks = 40, labels = seq(-999,1000,50)-1)
  RBP_binomial_table_template_stats <- RBP_binomial_table_template[ , .(Enrrichment=mean(Enrrichment), Enrrichment_l=mean(Enrrichment_l), Enrrichment_u=mean(Enrrichment_u))  , by=c( "exon_pos", "type",  "pos_int"  ) ]
  
  
  Total.Overlaps.template <- c()
  
  for (i in seq(-200, 200, 50)){
  
  O.Upstream <- Overlap(
  RBP_binomial_table_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="wG4", c("Enrrichment_l", "Enrrichment_u")],
  RBP_binomial_table_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="woG4", c("Enrrichment_l", "Enrrichment_u")]
  )
  
  O.Downstream <- Overlap(
  RBP_binomial_table_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="wG4", c("Enrrichment_l", "Enrrichment_u")],
  RBP_binomial_table_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="woG4", c("Enrrichment_l", "Enrrichment_u")]
  )
  
  Total.Overlaps.template <- rbind(Total.Overlaps.template, c(O.Upstream, O.Downstream))
  
  }
  
  
  
  
  if (0 %in% rbind(Total.Overlaps.non_template,  Total.Overlaps.template) ){
    
    
    head(RBP_binomial_table_non_template)
    
    RBP_binomial_table_non_template[, DNA_sense:="non_template"]
    RBP_binomial_table_template[, DNA_sense:="template"]
    
    RBP_binomial_table_non_template[, ID:=sample]
    RBP_binomial_table_template[, ID:=sample]
    
    figure6_table <- rbind(figure6_table, RBP_binomial_table_non_template)
    figure6_table <- rbind(figure6_table, RBP_binomial_table_template)
    
       
#    RBP_plot.non_template <- ggplot(RBP_binomial_table_non_template) +
#    geom_line(aes(x=Position, y=Enrrichment, color=type)) +
#     geom_ribbon(aes(ymin=Enrrichment_l, ymax=Enrrichment_u, x=Position, fill=type), alpha=0.3 )+
#    xlim(c(-250,250)) +
#    facet_grid(. ~ exon_pos  ) +
#    labs(colour = "100nt flanking intronic window", fill="100nt flanking intronic window") +
#    theme_bw() +
#    ggtitle(paste(metadata[`File accession`==sample, `Experiment target`], metadata[`File accession`==sample, `Biosample term name`], sample, "non-template")) +
#    theme(legend.position = "top", legend.direction = "horizontal") +
#    scale_fill_manual(values=c("#669900", "grey")) +  
#    scale_color_manual(values=c("#669900", "darkgrey"))
    
    
#    RBP_plot.template <-  ggplot(RBP_binomial_table_template) +
#    geom_line(aes(x=Position, y=Enrrichment, color=type)) +
#     geom_ribbon(aes(ymin=Enrrichment_l, ymax=Enrrichment_u, x=Position, fill=type), alpha=0.3 )+
#    xlim(c(-250,250)) +
#    facet_grid(. ~ exon_pos  ) +
#    labs(colour = "100nt flanking intronic window", fill="100nt flanking intronic window") +
#    theme_bw() +
#    ggtitle(paste(metadata[`File accession`==sample, `Experiment target` ], metadata[`File accession`==sample, `Biosample term name`],  sample, "template")) +
#    theme(legend.position = "top", legend.direction = "horizontal") +
#    scale_fill_manual(values=c("#669900", "grey")) +  
#    scale_color_manual(values=c("#669900", "darkgrey"))
    
    
#    pdf(paste0("./RBPs/plots/", sample , ".pdf")) 
#    plot_grid(RBP_plot.non_template, RBP_plot.template,  nrow =1)
#    dev.off() 
    
  }
  
  }


}


delta.non_template.rows <- c()
matrix.non_template.row_names <- c()
matrix.non_template <- c()

sample ="ENCFF639MYI"
#for (sample in samples){
  
#  if (length( list.files("./RBPs/", pattern = sample))==16 & (metadata[`File accession`==sample, Assembly]=="hg19" ) ){

  RBP_binomial_table_non_template <- plot_eql_diff_binomial_table(
  paste("./RBPs/exon.up_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.up_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.up_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.up_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  paste("./RBPs/exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
  110870 + 109467,
  108638 + 107433,
  3587 + 3431,
  5819 + 5465,
  0.05
  )

  RBP_binomial_table_non_template$pos_int <- cut(RBP_binomial_table_non_template$Position, breaks = 200, labels = seq(-999,1000,10)-1)
  RBP_binomial_table_non_template_stats <- RBP_binomial_table_non_template[ , .(Enrrichment=mean(Enrrichment), Enrrichment_l=mean(Enrrichment_l),   Enrrichment_u=mean(Enrrichment_u))  , by=c( "exon_pos", "type",  "pos_int"  ) ]
  
  
  Total.deltas.non_template.up <- c()
  Total.deltas.non_template.down <- c()
  
    for (i in seq(-200, 190, 10)){
    
    O.Upstream <- Overlap(
    RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="wG4", c("Enrrichment_l", "Enrrichment_u")],
    RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="woG4", c("Enrrichment_l", "Enrrichment_u")]
    )
    
    if (is.na(O.Upstream)){
      
      O.Upstream <- 1
    }
    
    O.Downstream <- Overlap(
    RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="wG4", c("Enrrichment_l", "Enrrichment_u")],
    RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="woG4", c("Enrrichment_l", "Enrrichment_u")]
    )
    
    if (is.na(O.Downstream)){
      
      O.Downstream <- 1
   }    
    
    delta.up <- 0
    
    if (O.Upstream==0 ) {
      
      delta.up <- RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="wG4", "Enrrichment"] - RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="woG4", "Enrrichment"]
      
      
    }
      
      
    delta.down <- 0
    
    if (O.Downstream==0 ) {
      
      delta.down <- RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="wG4", "Enrrichment"] - RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="woG4", "Enrrichment"]
      
      
    }
        
    Total.deltas.non_template.up <- c(Total.deltas.non_template.up, as.numeric(delta.up))
    Total.deltas.non_template.down <- c(Total.deltas.non_template.down, as.numeric(delta.down))
    
    }
  
  protein = metadata[`File accession`==sample, `Experiment target` ]
  cell_line = metadata[`File accession`==sample, `Biosample term name`]
  name = paste(protein, cell_line, sample, sep="_")
  
  
  matrix.non_template <- rbind(matrix.non_template, c(Total.deltas.non_template.up, Total.deltas.non_template.down))
  
  matrix.non_template.row_names <- c(matrix.non_template.row_names, name)


#  }
  
#}

Farm


delta.non_template.rows <- c()
matrix.non_template.row_names <- c()
matrix.non_template <- c()

for (sample in samples){
  
  if ( (length( list.files("./scores/", pattern = sample))==192 ) & (metadata[`File accession`==sample, Assembly]=="hg19" ) ) {

    RBP_binomial_table_non_template <- plot_eql_diff_binomial_table(
      paste("./scores/exon.up_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
      paste("./scores/exon.up_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
      paste("./scores/exon.down_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
      paste("./scores/exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.woG4.score.", sample, ".bed.list.out.num", sep=""),
      paste("./scores/exon.up_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
      paste("./scores/exon.up_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
      paste("./scores/exon.down_plus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_plus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
      paste("./scores/exon.down_minus.bed.filtered.100bp_intron.intersect_wao.All_G4.tsv.clean_minus_strand.wG4.score.", sample, ".bed.list.out.num", sep=""),
      110870 + 109467,
      108638 + 107433,
      3587 + 3431,
      5819 + 5465,
      0.05
    )

  RBP_binomial_table_non_template$pos_int <- cut(RBP_binomial_table_non_template$Position, breaks = 200, labels = seq(-999,1000,10)-1)
  RBP_binomial_table_non_template_stats <- RBP_binomial_table_non_template[ , .(Enrrichment=mean(Enrrichment), Enrrichment_l=mean(Enrrichment_l),   Enrrichment_u=mean(Enrrichment_u))  , by=c( "exon_pos", "type",  "pos_int"  ) ]
  
  
  Total.deltas.non_template.up <- c()
  Total.deltas.non_template.down <- c()
  
      for (i in seq(-200, 190, 10)){
    
    O.Upstream <- Overlap(
    RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="wG4", c("Enrrichment_l", "Enrrichment_u")],
    RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="woG4", c("Enrrichment_l", "Enrrichment_u")]
    )
    
    if (is.na(O.Upstream)){
      
      O.Upstream <- 1
    }
    
    O.Downstream <- Overlap(
    RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="wG4", c("Enrrichment_l", "Enrrichment_u")],
    RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="woG4", c("Enrrichment_l", "Enrrichment_u")]
    )
    
    if (is.na(O.Downstream)){
      
      O.Downstream <- 1
   }    
    
    delta.up <- 0
    
    if (O.Upstream==0 ) {
      
      delta.up <- RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="wG4", "Enrrichment"] - RBP_binomial_table_non_template_stats[ exon_pos=="Upstream" & pos_int==i & type=="woG4", "Enrrichment"]
      
      
    }
      
      
    delta.down <- 0
    
    if (O.Downstream==0 ) {
      
      delta.down <- RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="wG4", "Enrrichment"] - RBP_binomial_table_non_template_stats[ exon_pos=="Downstream" & pos_int==i & type=="woG4", "Enrrichment"]
      
      
    }
        
    Total.deltas.non_template.up <- c(Total.deltas.non_template.up, as.numeric(delta.up))
    Total.deltas.non_template.down <- c(Total.deltas.non_template.down, as.numeric(delta.down))
    
    }
  
  protein = metadata[`File accession`==sample, `Experiment target` ]
  cell_line = metadata[`File accession`==sample, `Biosample term name`]
  name = paste(protein, cell_line, sample, sep="_")
  
  
  matrix.non_template <- rbind(matrix.non_template, c(Total.deltas.non_template.up, Total.deltas.non_template.down))
  
  matrix.non_template.row_names <- c(matrix.non_template.row_names, name)


  }
  
}
rownames(matrix.non_template) <- matrix.non_template.row_names
Error: object 'matrix.non_template.row_names' not found
data_table.non_template <- fread("./RBPs/tables/non_template.RBP.matrix")
Detected 80 column names but the data has 81 columns (i.e. invalid file). Added 1 extra default column name for the first column which is guessed to be row names or an index. Use setnames() afterwards if this guess is not correct, or fix the file write command that created the file to create a valid file.
matrix.non_template <- as.matrix(data_table.non_template[, c(paste0("UP",  as.character(seq(-200,190, 10)) ), paste0("DOWN",  as.character(seq(-200,190, 10)) ))])
rownames(matrix.non_template) <- data_table.non_template$V1
matrix.non_template[which(!is.finite(matrix.non_template))] <- 0
matrix.non_template.filter <- matrix.non_template[ rowSums(abs(matrix.non_template))>30, ]
dim(matrix.non_template)
[1] 677  80
dim(matrix.non_template.filter)
[1] 352  80
test = matrix(rnorm(200), 20, 10)
test[1:10, seq(1, 10, 2)] = test[1:10, seq(1, 10, 2)] + 3
test[11:20, seq(2, 10, 2)] = test[11:20, seq(2, 10, 2)] + 2
test[15:20, seq(2, 10, 2)] = test[15:20, seq(2, 10, 2)] + 4
colnames(test) = paste("Test", 1:10, sep = "")
rownames(test) = paste("Name", 1:20, sep = "")

paletteLength <- 50
myColor <- colorRampPalette(c("blue", "white", "red"))(paletteLength)
# length(breaks) == length(paletteLength) + 1
# use floor and ceiling to deal with even/odd length pallettelengths
myBreaks <- c(seq(min(test), 0, length.out=ceiling(paletteLength/2) + 1), 
              seq(max(test)/paletteLength, max(test), length.out=floor(paletteLength/2)))
bk1 <- c(seq(-6,0.9,by=0.001),0.999)
bk2 <- c(1.001,seq(1.1,6,by=0.1))
bk <- c(bk1,bk2)  #combine the break limits for purpose of graphing
my_palette <- c(colorRampPalette(colors = c("darkblue", "lightblue"))(n = length(bk1)-1),
              "gray38", "gray38",
              c(colorRampPalette(colors = c("darkred", "tomato1"))(n = length(bk2)-1)))
my.breaks <- c(seq(-6, -0.001, by=0.001),
               seq(0.001, 6, by=0.001)) 
my.colors <- c(colorRampPalette(colors = c("darkblue", "lightblue", "antiquewhite"))(length(my.breaks)/2),
               colorRampPalette(colors = c("bisque", "red", "firebrick"))(length(my.breaks)/2))
RBP_heatmap.non_template <- pheatmap::pheatmap(matrix.non_template, fontsize = 4,   cutree_rows = 8, clustering_method = "ward.D", cluster_cols=F, 
                                               color = my.colors, breaks = my.breaks, scale = "none",
                                               show_rownames=F, show_colnames = F)

matrix.non_template["ZC3H8−human_K562_ENCFF207UUG",]
View(matrix.non_template)
View(data_table.non_template)

data_table.non_template[V1=="ZC3H8−human_K562_ENCFF207UUG", ]
data_table.template <- fread("./RBPs/tables/template.RBP.matrix")
Detected 80 column names but the data has 81 columns (i.e. invalid file). Added 1 extra default column name for the first column which is guessed to be row names or an index. Use setnames() afterwards if this guess is not correct, or fix the file write command that created the file to create a valid file.
matrix.template <- as.matrix(data_table.template[, c(paste0("UP",  as.character(seq(-200,190, 10)) ), paste0("DOWN",  as.character(seq(-200,190, 10)) ))])
rownames(matrix.template) <- data_table.template$V1
matrix.template[which(!is.finite(matrix.template))] <- 0
matrix.template.filter <- matrix.template[ rowSums(abs(matrix.template))>1, ]
dim(matrix.template.filter)
[1] 553  80
View(matrix.template.filter)

c(c(81:110 ), (131:160))

matrix.total[, c( c(1:30), c(51:110), (131:160) )    ]
RBP_heatmap.template <- pheatmap::pheatmap(matrix.template, fontsize = 4,   cutree_rows = 8, clustering_method = "ward.D", cluster_cols=F,
                                           color = my.colors, breaks = my.breaks, scale = "none",
                                           show_rownames=F, show_colnames = F)

library(ggalluvial)
package ‘ggalluvial’ was built under R version 3.5.2
library(plyr)
package ‘plyr’ was built under R version 3.5.2
Attaching package: ‘plyr’

The following object is masked from ‘package:matrixStats’:

    count

The following object is masked from ‘package:IRanges’:

    desc

The following object is masked from ‘package:S4Vectors’:

    rename
clustering.non_template <- hclust(dist(matrix.non_template), method = "ward.D")
clusters.non_template <- cutree(clustering.non_template, k=8)
clustering.template <- hclust(dist(matrix.template), method = "ward.D")
clusters.template <- cutree(clustering.template, k=8)
clustering.total <-  as.data.frame(cbind(clusters.non_template, clusters.template = clusters.template[names(clusters.non_template)]))
clustering.total$clusters.non_template <- mapvalues(clustering.total$clusters.non_template , 
          from =1:8,
          to = c("ns2", "iB2", "iB1", "iBsU", "ns1", "ieB2", "ieB1", "iBsD"))
clustering.total$clusters.template <- mapvalues(clustering.total$clusters.template , 
          from =1:8,
          to = c("ns1", "ns2", "ieB2", "iB1", "iB2", "iBsU", "iBsD", "ieB1"))
clustering.total$sample <- rownames(clustering.total)
clustering.total <- data.table(clustering.total)
clustering.total.stats <- clustering.total[ , .N , by =c("clusters.non_template", "clusters.template")]
ggplot(clustering.total.stats, aes(y=N, axis1=clusters.non_template, axis2=clusters.template)) +
  geom_alluvium( width = 1/12) +
  geom_stratum(width = 1/12, fill = "black", color = "grey") +
  geom_label(stat = "stratum", label.strata = TRUE) +
  scale_x_discrete(limits = c("clusters.non_template", "clusters.template"), expand = c(.05, .05))

ggplot(clustering.total.stats, aes(y=N, axis1=clusters.non_template, axis2=clusters.template)) +
  geom_alluvium(aes(fill=clusters.non_template=="ieB1"), width = 1/12) +
  geom_stratum(width = 1/12, fill = "black", color = "grey") +
  geom_label(stat = "stratum", label.strata = TRUE) +
  scale_x_discrete(limits = c("clusters.non_template", "clusters.template"), expand = c(.05, .05)) +
  theme(legend.position = "none") +
  scale_fill_manual(values=c("grey", "firebrick"))

ggplot(as.data.frame(UCBAdmissions),
       aes(y = Freq, axis1 = Gender, axis2 = Dept)) +
  geom_alluvium(aes(fill = Admit), width = 1/12) +
  geom_stratum(width = 1/12, fill = "black", color = "grey") +
  geom_label(stat = "stratum", label.strata = TRUE) +
  scale_x_discrete(limits = c("Gender", "Dept"), expand = c(.05, .05)) +
  scale_fill_brewer(type = "qual", palette = "Set1") 

matrix.total <- cbind(matrix.non_template, matrix.template)

matrix.total.trim <- matrix.total[, c( c(1:30), c(51:110), (131:160) )    ]


nt_t.colnames <-  c(paste0("ntUP",  as.character(seq(-200,190, 10)) ), paste0("ntDOWN",  as.character(seq(-200,190, 10)) ),  c(paste0("tUP",  as.character(seq(-200,190, 10)) ), paste0("tDOWN",  as.character(seq(-200,190, 10)) )) )



colnames(matrix.total) <- nt_t.colnames

New_fig.1 <- pheatmap::pheatmap(matrix.total.trim, fontsize = 4,   cutree_rows = 10, clustering_method = "ward.D", cluster_cols=F,
                                        color = my.colors, breaks = my.breaks, scale = "none",
                                        show_rownames=F, show_colnames = F, legend = T)

hc_rows <- hclust(dist(matrix.total.trim), method = "ward.D")

RBP_clusters <-  cutree(hc_rows, k=10)


RBP_clusters.table <- data.table(cbind(names(RBP_clusters), as.numeric(RBP_clusters)))

colnames(RBP_clusters.table) <- c("ID", "cluster")

RBP_clusters.table <- data.table(RBP_clusters.table)






RBP_clusters.table <- cbind(RBP_clusters.table, str_split_fixed(RBP_clusters.table$ID, "_", 3))


RBP_clusters.table <- cbind(RBP_clusters.table, str_split_fixed(RBP_clusters.table$V1, "-", 2))

RBP_clusters.table <- RBP_clusters.table[, c(1,2,4,5,6,7)]

colnames(RBP_clusters.table) <- c("ID", "cluster", "Cell", "File", "Gene", "Organism")




RBP_heatmap.total <- pheatmap::pheatmap(matrix.total.trim, fontsize = 4,   cutree_rows = 10, clustering_method = "ward.D", cluster_cols=F,
                                        color = my.colors, breaks = my.breaks, scale = "none",
                                        show_rownames=T, show_colnames = F)
ha = HeatmapAnnotation(df = anno1, anno_fun = anno2, ...)
Heatmap(matrix.total.trim, top_annotation = ha)

RNA-seq analysis


replace_p_value <- function(chisq_table){
  
  
  nrows <- nrow(chisq_table)
  print(chisq_table)
  
  for (i in 1:nrows) {
  

  
  conTable <- matrix(nrow = 2, c(chisq_table[i, eql_notG4] ,
                                 chisq_table[i, diff_notG4],
                                 chisq_table[i ,eql_G4],
                                 chisq_table[i, diff_G4] ))
  
  
  res <- chisq.test(conTable)
  chisq_table[i, p :=  res$p.value]
  chisq_table[i, chisq :=  as.numeric(res$statistic)]
  chisq_table[i, p.adj :=  res$p.value*nrows]
  
  i = i + 1
  
  }
}

library("ggrepel")

binomial_vulcano <- function(chisq_table){

  p <- ggplot() +
    geom_point(data = chisq_table, aes( logOR, -log(p.adj)  ), colour="grey", alpha=0.5  ) +
    geom_point(data = chisq_table[p.adj<0.05], aes( logOR, -log(p.adj) ) ,  colour="red", alpha=0.8   ) +
  
    geom_text_repel(data = chisq_table[p.adj<0.05 , ],
                    colour="black", aes( logOR, -log(p.adj),
                    #nudge_y      = 3,
                    #direction    = "x",
                    #angle        = 90,
                    #vjust        = 1,
                    #segment.size = 0.2,
                    #label.size = 0.05,
                    label=chisq_table[p.adj<0.05 , mut]))   +
    
    theme_bw()
  
  return(p)


}
template_non_template.chisq <-  fread("./shRNA_RBP/TOTAL.chisquared.txt")

non_template.chisq <-  fread("./shRNA_RBP/Non_template.chisquared.txt")
template.chisq <-  fread("./shRNA_RBP/Template.chisquared.txt")

non_template_upstream.chisq <-  fread("./shRNA_RBP/Non_template_upstream.chisquared.txt")
non_template_downstream.chisq <-  fread("./shRNA_RBP/Non_template_downstream.chisquared.txt")
template_upstream.chisq <-  fread("./shRNA_RBP/Template_upstream.chisquared.txt")
template_downstream.chisq <-  fread("./shRNA_RBP/Template_downstream.chisquared.txt")


replace_p_value(template_non_template.chisq)
replace_p_value(non_template.chisq)
replace_p_value(template.chisq)

replace_p_value(non_template_upstream.chisq)
replace_p_value(non_template_downstream.chisq)
replace_p_value(template_upstream.chisq)
replace_p_value(template_downstream.chisq)
template_non_template.chisq <- cbind(template_non_template.chisq,  str_split_fixed(template_non_template.chisq$mut, "_", 2))
colnames(template_non_template.chisq) <- c("mut", "control", "eql_notG4", "eql_G4", "diff_notG4", "diff_G4", "logOR", "chisq", "p", "p.adj", "Cell", "Gene" ) 

non_template.chisq <- cbind(non_template.chisq,  str_split_fixed(non_template.chisq$mut, "_", 2))
colnames(non_template.chisq) <- c("mut", "control", "eql_notG4", "eql_G4", "diff_notG4", "diff_G4", "logOR", "chisq", "p", "p.adj", "Cell", "Gene" ) 

template.chisq <- cbind(template.chisq,  str_split_fixed(template.chisq$mut, "_", 2))
colnames(template.chisq) <- c("mut", "control", "eql_notG4", "eql_G4", "diff_notG4", "diff_G4", "logOR", "chisq", "p", "p.adj", "Cell", "Gene" ) 




RBP_clusters_total.chsq <-merge(RBP_clusters.table, template_non_template.chisq, by=c("Cell", "Gene"), all.x=TRUE)

RBP_clusters_non_template.chsq <-merge(RBP_clusters.table, non_template.chisq, by=c("Cell", "Gene"), all.x=TRUE)

RBP_clusters_template.chsq <-merge(RBP_clusters.table, template.chisq, by=c("Cell", "Gene"), all.x=TRUE)


RBP_clusters_total.chsq[ ,orientation:="Both"]
RBP_clusters_non_template.chsq[ ,orientation:="Non_template"]
RBP_clusters_template.chsq[ ,orientation:="Template"]

RBP_clusters_ALL.chsq <- rbind(RBP_clusters_total.chsq, RBP_clusters_non_template.chsq, RBP_clusters_template.chsq)


row.order <- RBP_heatmap.total$tree_row$order 

RBP_clusters_ALL.chsq$ID <- factor(RBP_clusters_ALL.chsq$ID, levels=rev(RBP_clusters.table[row.order, ]$ID) )


 

pos <- position_jitter(width = 0.3, seed = 2)


RBP_clusters_ALL.chsq[  p.adj>0.05 ,colour:="non significant" ]
RBP_clusters_ALL.chsq[  p.adj<=0.05 &  Cell=="HepG2", colour:="HepG2" ]
RBP_clusters_ALL.chsq[  p.adj<=0.05  & Cell=="K562", colour:="K562" ]

filtered_factors <- RBP_clusters_ALL.chsq[ p.adj<=0.05 , .(.N) , by=c("Gene", "Cell", "cluster", "orientation" )][N>=2, paste0(Gene, Cell, cluster, orientation ) ]

  
New_fig.2 <-    ggplot(RBP_clusters_ALL.chsq) +
  geom_jitter(aes(x=ID, y=logOR, colour=colour ) ) +
  coord_flip() +
  theme_bw() +
  theme(legend.position = "top") +
  scale_x_discrete(labels= rev(RBP_clusters.table[row.order, ]$cluster)) +
  facet_grid( . ~ orientation ) +
  scale_color_manual(values=c("forestgreen", "purple", "grey")) +
  geom_label_repel(data=RBP_clusters_ALL.chsq[ p.adj<=0.05 & paste0(Gene, Cell, cluster, orientation ) %in% filtered_factors , ], aes(x=ID, y=logOR, label=Gene, ), 
                   label.size = 0.01,
                   position = pos,
                   alpha = 0.6, 
                   label.padding=.1 )
  

New_fig.2



non_template_upstream.chisq <- cbind(non_template_upstream.chisq,  str_split_fixed(non_template_upstream.chisq$mut, "_", 2))
colnames(non_template_upstream.chisq) <- c("mut", "control", "eql_notG4", "eql_G4", "diff_notG4", "diff_G4", "logOR", "chisq", "p", "p.adj", "Cell", "Gene" ) 

non_template_downstream.chisq <- cbind(non_template_downstream.chisq,  str_split_fixed(non_template_downstream.chisq$mut, "_", 2))
colnames(non_template_downstream.chisq) <- c("mut", "control", "eql_notG4", "eql_G4", "diff_notG4", "diff_G4", "logOR", "chisq", "p", "p.adj", "Cell", "Gene" ) 

template_upstream.chisq <- cbind(template_upstream.chisq,  str_split_fixed(template_upstream.chisq$mut, "_", 2))
colnames(template_upstream.chisq) <- c("mut", "control", "eql_notG4", "eql_G4", "diff_notG4", "diff_G4", "logOR", "chisq", "p", "p.adj", "Cell", "Gene" ) 

template_downstream.chisq <- cbind(template_downstream.chisq,  str_split_fixed(template_downstream.chisq$mut, "_", 2))
colnames(template_downstream.chisq) <- c("mut", "control", "eql_notG4", "eql_G4", "diff_notG4", "diff_G4", "logOR", "chisq", "p", "p.adj", "Cell", "Gene" )



#RBP_clusters_total.chsq <-merge(RBP_clusters.table, template_non_template.chisq, by=c("Cell", "Gene"), all.x=TRUE)

RBP_clusters_non_template_upstream.chsq <-merge(RBP_clusters.table, non_template_upstream.chisq, by=c("Cell", "Gene"), all.x=TRUE)
RBP_clusters_non_template_downstream.chsq <-merge(RBP_clusters.table, non_template_downstream.chisq, by=c("Cell", "Gene"), all.x=TRUE)

RBP_clusters_template_upstream.chsq <-merge(RBP_clusters.table, template_upstream.chisq, by=c("Cell", "Gene"), all.x=TRUE)
RBP_clusters_template_downstream.chsq <-merge(RBP_clusters.table, template_downstream.chisq, by=c("Cell", "Gene"), all.x=TRUE)


RBP_clusters_total.chsq[ ,orientation:="Total"]
RBP_clusters_non_template_upstream.chsq[ ,orientation:="Non_template_upstream"]
RBP_clusters_non_template_downstream.chsq[ ,orientation:="Non_template_downstream"]
RBP_clusters_template_upstream.chsq[ ,orientation:="Template_upstream"]
RBP_clusters_template_downstream.chsq[ ,orientation:="Template_downstream"]

RBP_clusters_ALL.chsq <- rbind(RBP_clusters_total.chsq, 
                               RBP_clusters_non_template_upstream.chsq,
                               RBP_clusters_non_template_downstream.chsq,
                               RBP_clusters_template_upstream.chsq,
                               RBP_clusters_template_downstream.chsq)


row.order <- RBP_heatmap.total$tree_row$order 

RBP_clusters_ALL.chsq$ID <- factor(RBP_clusters_ALL.chsq$ID, levels=rev(RBP_clusters.table[row.order, ]$ID) )


 
human_diff[ !is.na(Gene), .(Gene, log2FoldChange=-log2FoldChange, padj) ]


pos <- position_jitter(width = 0.3, seed = 2)


RBP_clusters_ALL.chsq[  p.adj>0.05 ,colour:="non significant" ]
RBP_clusters_ALL.chsq[  p.adj<=0.05 &  Cell=="HepG2", colour:="HepG2" ]
RBP_clusters_ALL.chsq[  p.adj<=0.05  & Cell=="K562", colour:="K562" ]


RBP_clusters_ALL.chsq[ , sig_KCl:=(Gene %in% human_diff[padj<0.05 & !is.na(Gene), Gene])]

filtered_factors <- RBP_clusters_ALL.chsq[ p.adj<=0.05  , .(.N) , by=c("Gene", "Cell", "cluster", "orientation" )][N>=2, paste0(Gene, Cell, cluster, orientation ) ]
RBP_clusters_ALL.chsq$orientation <- factor(RBP_clusters_ALL.chsq$orientation, levels = c("Total", "Non_template_upstream", "Non_template_downstream", "Template_upstream", "Template_downstream"   ))
RBP_clusters_ALL.chsq.KCl <- merge(RBP_clusters_ALL.chsq, human_diff[ !is.na(Gene), .(Gene, log2FoldChange=-log2FoldChange, padj.KCl=padj) ], by="Gene")

filtered_factors.KCL <- unique(RBP_clusters_ALL.chsq.KCl[  , .(.N) , by=c("Gene", "Cell", "cluster", "orientation" )][N>=2, Gene ])
RBP_clusters_ALL.chsq.KCl$orientation <- factor(RBP_clusters_ALL.chsq.KCl$orientation, levels = c("Total", "Non_template_upstream", "Non_template_downstream", "Template_upstream", "Template_downstream"   ))

ggplot(RBP_clusters_ALL.chsq.KCl) +
  geom_jitter(aes(x=ID, y=log2FoldChange, colour=colour ) ) +
  coord_flip() +
  theme_bw() +
  theme(legend.position = "top") +
  scale_x_discrete(labels= rev(RBP_clusters.table[row.order, ]$cluster)) +
  scale_color_manual(values=c("forestgreen", "purple", "grey")) +
  geom_label_repel(data=RBP_clusters_ALL.chsq.KCl[  paste0(Gene, Cell, cluster, orientation ) %in% filtered_factors.KCL , ], aes(x=ID, y=log2FoldChange, label=Gene, ), 
                   label.size = 0.01,
                   position = pos,
                   alpha = 0.6, 
                   label.padding=.1 )
RBP_clusters_ALL.chsq[File=="ENCFF241SUC",]
 ggplot(RBP_clusters_ALL.chsq) +
  geom_jitter(aes(x=ID, y=logOR, colour=colour ) ) +
  coord_flip() +
  theme_bw() +
  theme(legend.position = "top") +
  scale_x_discrete(labels= rev(RBP_clusters.table[row.order, ]$cluster)) +
  facet_grid( . ~ orientation ) +
  scale_color_manual(values=c("forestgreen", "purple", "grey")) +
  geom_label_repel(data=RBP_clusters_ALL.chsq[ p.adj<=0.05 & paste0(Gene, Cell, cluster, orientation ) %in% filtered_factors , ], aes(x=ID, y=logOR, label=Gene, ), 
                   label.size = 0.01,
                   position = pos,
                   alpha = 0.6, 
                   label.padding=.1 )

RBP_clusters_ALL.chsq$cluster <- factor(RBP_clusters_ALL.chsq$cluster, levels=c(4,8,5,9,3,6,10,1,2,7))

New_fig.2 <- ggplot(RBP_clusters_ALL.chsq) +
  geom_jitter(aes(x=ID, y=logOR, colour=colour ) ) +
  coord_flip() +

  scale_x_discrete(labels= rev(RBP_clusters.table[row.order, ]$cluster)) +
  facet_grid( cluster ~ orientation, scales = "free_y", space = "free_y", switch = "y" ) +
  scale_color_manual(values=c("forestgreen", "purple", "grey")) +
  geom_label_repel(data=RBP_clusters_ALL.chsq[p.adj<=0.05 &   paste0(Gene, Cell, cluster, orientation ) %in% filtered_factors , ], aes(x=ID, y=logOR, label=Gene, ), 

                    #force = 0.5,
                    nudge_x = 1,
                    #direction = "y",
                    #hjust = 0,
                    segment.size = 0.5,
                    #segment.curvature = -0.1,
                   label.size = 0.01,
                   size = 2.5,
                   #position = pos,
                   alpha = 0.6, 
                   label.padding=0.001,
                   max.iter=10000) +
  theme_bw() +
  theme(legend.position = "top",
        axis.title.y=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),)
  

New_fig.2
library("ggplotify")
Error in library("ggplotify") : there is no package called ‘ggplotify’



ggplot(RBP_clusters_ALL.chsq) +
  geom_jitter(aes(x=ID, y=logOR, colour=p.adj <= 0.05) ) +
  coord_flip() +
  theme_bw() +
  theme(legend.position = "none") +
  scale_x_discrete(labels= rev(RBP_clusters.table[row.order, ]$cluster)) +
  facet_grid( ~ orientation ) +
  scale_color_manual(values=c("grey", "red")) +
  

  geom_text_repel(data = chisq_table[p.adj<0.05 , ],
                    colour="black", aes( logOR, -log(p.adj),
                    label=chisq_table[p.adj<0.05 , mut]))   +
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:Hmisc’:

    src, summarize

The following objects are masked from ‘package:plyr’:

    arrange, count, desc, failwith, id, mutate, rename, summarise, summarize

The following objects are masked from ‘package:data.table’:

    between, first, last

The following object is masked from ‘package:biomaRt’:

    select

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
binomial_vulcano(non_template.chisq)
Error in ggplot() : could not find function "ggplot"
binomial_vulcano(template.chisq)

binomial_vulcano(Non_template_downstream.chisq)
template_non_template.chisq[p.adj<0.05]
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQoKCgoKYGBge3J9CmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvd3Bsb3QpCmBgYAoKCgoKYGBge3J9CmxpYnJhcnkoRGVzY1Rvb2xzKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KEhtaXNjKQpsaWJyYXJ5KGNvd3Bsb3QpCgpgYGAKCgoKYGBge3J9CmZ1bmNfYW5ub3RhdGlvbiA8LSBkYXRhLnRhYmxlKHJlYWRfZXhjZWwoIi9Vc2Vycy9ncDcvR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTm9uX0IvcG90YXNzaXVtX2V4cGVyaW1lbnRzL0RHQS8xMzA1OV8yMDIwXzE5ODJfTU9FU00yX0VTTS54bHN4IikpCmBgYAoKCmBgYHtyfQpodW1hbl9kaWZmIDwtIGZyZWFkKCcvVXNlcnMvZ3A3L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL05vbl9CL3BvdGFzc2l1bV9leHBlcmltZW50cy9ER0EvY29udHJvbC12cy1LQ2wuZGlmZmV4cC50c3YnKQoKaHVtYW5fZGlmZlsgLCBJRDo9Z3N1YigiXFwuLioiLCIiLCBWMSldCgpodW1hbl9kaWZmIDwtIG1lcmdlKGh1bWFuX2RpZmYsIGZ1bmNfYW5ub3RhdGlvbiwgYnk9IklEIiwgYWxsLnggPSBUKQoKCmh1bWFuX2RpZmZbIWlzLm5hKEdlbmUpXQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MzAsIGZpZy5oZWlnaHQ9MTB9CgpodW1hbl9kaWZmWyBTcGxpY2Vvc29tZT09MSAsIGNsYXNzOj0nU3BsaWNlb3NvbWUnXQpodW1hbl9kaWZmWyAoYFNwbGljaW5nIHJlZ3VsYXRpb25gPT0xICYgU3BsaWNlb3NvbWU9PTApICwgY2xhc3M6PSdTcGxpY2luZyByZWd1bGF0aW9uJ10KaHVtYW5fZGlmZlsgSGVsaWNhc2U9PTEgLCBjbGFzczo9J0hlbGljYXNlcyddCgpodW1hbl9kaWZmJGNsYXNzIDwtIGZhY3RvcihodW1hbl9kaWZmJGNsYXNzLCBsZXZlbHM9YygnU3BsaWNlb3NvbWUnLCAnU3BsaWNpbmcgcmVndWxhdGlvbicsICdIZWxpY2FzZXMnKSApCgoKCgoKZ2dwbG90KCkgKwpnZW9tX3BvaW50KGRhdGEgPSBodW1hbl9kaWZmWyFpcy5uYShHZW5lKSAmICFpcy5uYShjbGFzcykgLCBdLCBhZXMoIC1sb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopICApLCBjb2xvdXI9ImdyZXkiLCBhbHBoYT0wLjUgICkrCmdlb21fcG9pbnQoZGF0YSA9IGh1bWFuX2RpZmZbIWlzLm5hKEdlbmUpICAmIHBhZGo8MC4wNSAmICFpcy5uYShjbGFzcykgLCBdLCBhZXMoIC1sb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopICkgLCAgY29sb3VyPSJyZWQiLCBhbHBoYT0wLjggICApICsKZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBodW1hbl9kaWZmWyFpcy5uYShHZW5lKSAmIHBhZGo8MC4wNSAmICFpcy5uYShjbGFzcykgLCBdLAogICAgICAgICAgICAgICAgY29sb3VyPSJibGFjayIsIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaiksCiAgICAgICAgICAgICAgICBsYWJlbD1odW1hbl9kaWZmW3BhZGo8MC4wNSAmICFpcy5uYShjbGFzcykgICwgR2VuZV0pLAogICAgICAgICAgICAgICAgZm9yY2UgPSAxLjUKICAgICAgICAgICAgICAgICkgICArICAKICBmYWNldF9ncmlkKC4gfiBjbGFzcykgKwp4bGltKGMoLTEsMSkpICsKeGxhYihleHByZXNzaW9uKGxvZ1syXX5Gb2xkfkNoYW5nZSkpKwp5bGFiKGV4cHJlc3Npb24gKGxvZ1sxMF1+IkFkanVzdGVkIHAtdmFsdWUiKSkrCnRoZW1lX2J3KCkKYGBgCgoKYGBge3J9Cgp2dWxjYW5vLnNwbGljZW9zb21lIDwtIGdncGxvdCgpICsKZ2VvbV9wb2ludChkYXRhID0gaHVtYW5fZGlmZlshaXMubmEoR2VuZSldLCBhZXMoIC1sb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopICApLCBjb2xvdXI9ImdyZXkiLCBhbHBoYT0wLjUgICkrCiAgZ2VvbV9wb2ludChkYXRhID0gaHVtYW5fZGlmZltwYWRqPDAuMDUgJiAgU3BsaWNlb3NvbWU9PTEgLCBdLCBhZXMoIC1sb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopICkgLCAgY29sb3VyPSJvcmFuZ2UiLCBhbHBoYT0wLjggICApICsKZ2VvbV9wb2ludChkYXRhID0gaHVtYW5fZGlmZltwYWRqPDAuMDUgJiBhYnMobG9nMkZvbGRDaGFuZ2UpPj0wLjUgJiAgU3BsaWNlb3NvbWU9PTEgLCBdLCBhZXMoIC1sb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopICkgLCAgY29sb3VyPSJyZWQiLCBhbHBoYT0wLjggICApICsKZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBodW1hbl9kaWZmW3BhZGo8MC4wNSAmIFNwbGljZW9zb21lPT0xICwgXSwKICAgICAgICAgICAgICAgIGNvbG91cj0iYmxhY2siLCBhZXMoIC1sb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopLAogICAgICAgICAgICAgICAgbGFiZWw9aHVtYW5fZGlmZltwYWRqPDAuMDUgJiAgU3BsaWNlb3NvbWU9PTEgLCBHZW5lXSksCiAgICAgICAgICAgICAgICBmb3JjZSA9IDEuNQogICAgICAgICAgICAgICAgI251ZGdlX3ggICAgICA9IDAuMwogICAgICAgICAgICAgICAgI2RpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICNhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICN2anVzdCAgICAgICAgPSAxLAogICAgICAgICAgICAgICAgI3NlZ21lbnQuc2l6ZSA9IDEsCiAgICAgICAgICAgICAgICAjbGFiZWwuc2l6ZSA9IDAuMDUsCiAgICAgICAgICAgICAgICApICAgKyAgCnhsaW0oYygtMSwxKSkgKwp4bGFiKGV4cHJlc3Npb24obG9nWzJdfkZvbGR+Q2hhbmdlKSkrCnlsYWIoZXhwcmVzc2lvbiAoLWxvZ1sxMF1+IkFkanVzdGVkIHAtdmFsdWUiKSkrCnRoZW1lX2J3KCkKCgp2dWxjYW5vLmZhY3RvcnMgPC0gZ2dwbG90KCkgKwpnZW9tX3BvaW50KGRhdGEgPSBodW1hbl9kaWZmWyFpcy5uYShHZW5lKV0sIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaikgICksIGNvbG91cj0iZ3JleSIsIGFscGhhPTAuNSAgKSsKZ2VvbV9wb2ludChkYXRhID0gaHVtYW5fZGlmZltwYWRqPDAuMDUgJiAoYFNwbGljaW5nIHJlZ3VsYXRpb25gPT0xICYgU3BsaWNlb3NvbWU9PTApICAsIF0sIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaikgKSAsICBjb2xvdXI9Im9yYW5nZSIsIGFscGhhPTAuOCAgICkgKyAgCmdlb21fcG9pbnQoZGF0YSA9IGh1bWFuX2RpZmZbcGFkajwwLjA1ICYgYWJzKGxvZzJGb2xkQ2hhbmdlKT49MC41ICYgKGBTcGxpY2luZyByZWd1bGF0aW9uYD09MSAmIFNwbGljZW9zb21lPT0wKSAsIF0sIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaikgKSAsICBjb2xvdXI9InJlZCIsIGFscGhhPTAuOCAgICkgKwpnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGh1bWFuX2RpZmZbcGFkajwwLjA1ICYgKGBTcGxpY2luZyByZWd1bGF0aW9uYD09MSAmIFNwbGljZW9zb21lPT0wKSAgLCBdLAogICAgICAgICAgICAgICAgY29sb3VyPSJibGFjayIsIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaiksCiAgICAgICAgICAgICAgICBsYWJlbD1odW1hbl9kaWZmW3BhZGo8MC4wNSAmIChgU3BsaWNpbmcgcmVndWxhdGlvbmA9PTEgJiBTcGxpY2Vvc29tZT09MCkgICAsIEdlbmVdKSwKICAgICAgICAgICAgICAgIGZvcmNlID0gMS41LAogICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gSW5mLAogICAgICAgICAgICAgICAgI251ZGdlX3ggICAgICA9IDAuMwogICAgICAgICAgICAgICAgI2RpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICNhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICN2anVzdCAgICAgICAgPSAxLAogICAgICAgICAgICAgICAgI3NlZ21lbnQuc2l6ZSA9IDEsCiAgICAgICAgICAgICAgICAjbGFiZWwuc2l6ZSA9IDAuMDUsCiAgICAgICAgICAgICAgICApICAgKyAgCnhsaW0oYygtMSwxKSkgKwp4bGFiKGV4cHJlc3Npb24obG9nWzJdfkZvbGR+Q2hhbmdlKSkrCnlsYWIoZXhwcmVzc2lvbiAoLWxvZ1sxMF1+IkFkanVzdGVkIHAtdmFsdWUiKSkrCnRoZW1lX2J3KCkKCnZ1bGNhbm8uaGVsaWNhc2UgPC0gZ2dwbG90KCkgKwpnZW9tX3BvaW50KGRhdGEgPSBodW1hbl9kaWZmWyFpcy5uYShHZW5lKV0sIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaikgICksIGNvbG91cj0iZ3JleSIsIGFscGhhPTAuNSAgKSsKICBnZW9tX3BvaW50KGRhdGEgPSBodW1hbl9kaWZmW3BhZGo8MC4wNSAgJiAgKEhlbGljYXNlPT0xKSAsIF0sIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaikgKSAsICBjb2xvdXI9Im9yYW5nZSIsIGFscGhhPTAuOCAgICkgKwpnZW9tX3BvaW50KGRhdGEgPSBodW1hbl9kaWZmW3BhZGo8MC4wNSAmICBhYnMobG9nMkZvbGRDaGFuZ2UpPj0wLjUgJiAgKEhlbGljYXNlPT0xKSAsIF0sIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaikgKSAsICBjb2xvdXI9InJlZCIsIGFscGhhPTAuOCAgICkgKwpnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGh1bWFuX2RpZmZbcGFkajwwLjA1ICYgKEhlbGljYXNlPT0xKSAsIF0sCiAgICAgICAgICAgICAgICBjb2xvdXI9ImJsYWNrIiwgYWVzKCAtbG9nMkZvbGRDaGFuZ2UsIC1sb2cxMChwYWRqKSwKICAgICAgICAgICAgICAgIGxhYmVsPWh1bWFuX2RpZmZbcGFkajwwLjA1ICYgKEhlbGljYXNlPT0xKSAgLCBHZW5lXSksCiAgICAgICAgICAgICAgICBmb3JjZSA9IDEuNQogICAgICAgICAgICAgICAgI251ZGdlX3ggICAgICA9IDAuMwogICAgICAgICAgICAgICAgI2RpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICNhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICN2anVzdCAgICAgICAgPSAxLAogICAgICAgICAgICAgICAgI3NlZ21lbnQuc2l6ZSA9IDEsCiAgICAgICAgICAgICAgICAjbGFiZWwuc2l6ZSA9IDAuMDUsCiAgICAgICAgICAgICAgICApICAgKyAgCnhsaW0oYygtMSwxKSkgKwp4bGFiKGV4cHJlc3Npb24obG9nWzJdfkZvbGR+Q2hhbmdlKSkrCnlsYWIoZXhwcmVzc2lvbG9nWzEwXX4iQWRqdXN0ZWQgcC12YWx1ZSIpKSsKdGhlbWVfYncoKQpgYGAKCgoKYGBge3J9CnZ1bGNhbm8uZmFjdG9ycyA8LSBnZ3Bsb3QoKSArCmdlb21fcG9pbnQoZGF0YSA9IGh1bWFuX2RpZmZbIWlzLm5hKEdlbmUpXSwgYWVzKCAtbG9nMkZvbGRDaGFuZ2UsIC1sb2cxMChwYWRqKSAgKSwgY29sb3VyPSJncmV5IiwgYWxwaGE9MC41ICApKwpnZW9tX3BvaW50KGRhdGEgPSBodW1hbl9kaWZmW3BhZGo8MC4wNSAmIChgU3BsaWNpbmcgcmVndWxhdGlvbmA9PTEgJiBTcGxpY2Vvc29tZT09MCkgICwgXSwgYWVzKCAtbG9nMkZvbGRDaGFuZ2UsIC1sb2cxMChwYWRqKSApICwgIGNvbG91cj0ib3JhbmdlIiwgYWxwaGE9MC44ICAgKSArICAKZ2VvbV9wb2ludChkYXRhID0gaHVtYW5fZGlmZltwYWRqPDAuMDUgJiBhYnMobG9nMkZvbGRDaGFuZ2UpPj0wLjUgJiAoYFNwbGljaW5nIHJlZ3VsYXRpb25gPT0xICYgU3BsaWNlb3NvbWU9PTApICwgXSwgYWVzKCAtbG9nMkZvbGRDaGFuZ2UsIC1sb2cxMChwYWRqKSApICwgIGNvbG91cj0icmVkIiwgYWxwaGE9MC44ICAgKSArCmdlb21fdGV4dF9yZXBlbChkYXRhID0gaHVtYW5fZGlmZltwYWRqPDAuMDUgJiAoYFNwbGljaW5nIHJlZ3VsYXRpb25gPT0xICYgU3BsaWNlb3NvbWU9PTApICYgYWJzKGxvZzJGb2xkQ2hhbmdlKT49MC41ICAsIF0sCiAgICAgICAgICAgICAgICBjb2xvdXI9ImJsYWNrIiwgYWVzKCAtbG9nMkZvbGRDaGFuZ2UsIC1sb2cxMChwYWRqKSwKICAgICAgICAgICAgICAgIGxhYmVsPWh1bWFuX2RpZmZbcGFkajwwLjA1ICYgKGBTcGxpY2luZyByZWd1bGF0aW9uYD09MSAmIFNwbGljZW9zb21lPT0wKSAmIGFicyhsb2cyRm9sZENoYW5nZSk+PTAuNSAmICAsIEdlbmVdKSwKICAgICAgICAgICAgICAgIGZvcmNlID0gMS41CiAgICAgICAgICAgICAgICAjbnVkZ2VfeCAgICAgID0gMC4zCiAgICAgICAgICAgICAgICAjZGlyZWN0aW9uICAgID0gIngiLAogICAgICAgICAgICAgICAgI2FuZ2xlICAgICAgICA9IDkwLAogICAgICAgICAgICAgICAgI3ZqdXN0ICAgICAgICA9IDEsCiAgICAgICAgICAgICAgICAjc2VnbWVudC5zaXplID0gMSwKICAgICAgICAgICAgICAgICNsYWJlbC5zaXplID0gMC4wNSwKICAgICAgICAgICAgICAgICkgICArICAKeGxpbShjKC0xLDEpKSArCnhsYWIoZXhwcmVzc2lvbihsb2dbMl1+Rm9sZH5DaGFuZ2UpKSsKeWxhYihleHByZXNzaW9uIChsb2dbMTBdfiJBZGp1c3RlZCBwLXZhbHVlIikpKwp0aGVtZV9idygpCmBgYAoKCmBgYHtyfQp2dWxjYW5vLmZhY3RvcnMKCmBgYAoKCmBgYHtyfQpnZ3Bsb3QoKSArCmdlb21fcG9pbnQoZGF0YSA9IGh1bWFuX2RpZmYsIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaikgICksIGNvbG91cj0iZ3JleSIsIGFscGhhPTAuNSAgKSsKZ2VvbV9wb2ludChkYXRhID0gaHVtYW5fZGlmZlsgIHBhZGo8MC4wNSAmIGFicyhsb2cyRm9sZENoYW5nZSk+PTAuNSAsIF0sIGFlcyggLWxvZzJGb2xkQ2hhbmdlLCAtbG9nMTAocGFkaikgKSAsICBjb2xvdXI9InJlZCIsIGFscGhhPTAuOCAgICkgKwoKeGxhYihleHByZXNzaW9uKGxvZ1syXX5Gb2xkfkNoYW5nZSkpKwp5bGFiKGV4cHJlc3Npb24gKGxvZ1sxMF1+IkFkanVzdGVkIHAtdmFsdWUiKSkrCnRoZW1lX2J3KCkKYGBgCgoKYGBge3J9CmdncGxvdCgpICsKZ2VvbV9wb2ludChkYXRhID0gaHVtYW5fZGlmZlshaXMubmEoR2VuZSldLCBhZXMoIC1sb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopICApLCBjb2xvdXI9ImdyZXkiLCBhbHBoYT0wLjUgICkrCmdlb21fcG9pbnQoZGF0YSA9IGh1bWFuX2RpZmZbKEdlbmUgJWluJSBmaWx0ZXJlZF9mYWN0b3JzLktDTCkgJiBwYWRqPDAuMDUgJiBhYnMobG9nMkZvbGRDaGFuZ2UpPj0wLjUgLCBdLCBhZXMoIC1sb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopICkgLCAgY29sb3VyPSJyZWQiLCBhbHBoYT0wLjggICApICsKZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBodW1hbl9kaWZmWyhHZW5lICVpbiUgZmlsdGVyZWRfZmFjdG9ycy5LQ0wpICYgcGFkajwwLjA1ICYgYWJzKGxvZzJGb2xkQ2hhbmdlKT49MC41ICwgXSwKICAgICAgICAgICAgICAgIGNvbG91cj0iYmxhY2siLCBhZXMoIC1sb2cyRm9sZENoYW5nZSwgLWxvZzEwKHBhZGopLAogICAgICAgICAgICAgICAgbGFiZWw9aHVtYW5fZGlmZlsoR2VuZSAlaW4lIGZpbHRlcmVkX2ZhY3RvcnMuS0NMKSAmIHBhZGo8MC4wNSAmIGFicyhsb2cyRm9sZENoYW5nZSk+PTAuNSAgLCBHZW5lXSksCiAgICAgICAgICAgICAgICBmb3JjZSA9IDEuNQogICAgICAgICAgICAgICAgI251ZGdlX3ggICAgICA9IDAuMwogICAgICAgICAgICAgICAgI2RpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICNhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICN2anVzdCAgICAgICAgPSAxLAogICAgICAgICAgICAgICAgI3NlZ21lbnQuc2l6ZSA9IDEsCiAgICAgICAgICAgICAgICAjbGFiZWwuc2l6ZSA9IDAuMDUsCiAgICAgICAgICAgICAgICApICAgKyAgCnhsaW0oYygtMSwxKSkgKwp4bGFiKGV4cHJlc3Npb24obG9nWzJdfkZvbGR+Q2hhbmdlKSkrCnlsYWIoZXhwcmVzc2lvbiAobG9nWzEwXX4iQWRqdXN0ZWQgcC12YWx1ZSIpKSsKdGhlbWVfYncoKQpgYGAKCgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQoKcGxvdF9ncmlkKHZ1bGNhbm8uc3BsaWNlb3NvbWUsIHZ1bGNhbm8uZmFjdG9ycywgbGFiZWxzID0gIkFVVE8iLCByb3dzID0gMSkKCmBgYAoKCgpgYGB7cn0KaHVtYW5fZGlmZltwYWRqPDAuMDUgJiAhaXMubmEoR2VuZSksXVtvcmRlcigtYWJzKGxvZzJGb2xkQ2hhbmdlKSApXQpodW1hbl9kaWZmW3BhZGo8MC4wNSAmIGFicyhsb2cyRm9sZENoYW5nZSk+PTAuNSAmICFpcy5uYShHZW5lKSxdW29yZGVyKC1hYnMobG9nMkZvbGRDaGFuZ2UpICldCmBgYAoKCgojIyMjIyMjCgpFeHBlcmltZW50YWwgdHJhbnNpdGlvbiBmaWd1cmUKCgpgYGB7cn0KbWF0cml4LnRvdGFsLmRlbHRhX3N1bXMgPC0gYXMuZGF0YS5mcmFtZShjYmluZChyb3dTdW1zKG1hdHJpeC5ub25fdGVtcGxhdGUpLCByb3dTdW1zKG1hdHJpeC50ZW1wbGF0ZSkpKQoKbWF0cml4LnRvdGFsLmRlbHRhX3N1bXMkSUQgPC0gIHJvd25hbWVzKG1hdHJpeC50b3RhbC5kZWx0YV9zdW1zKQoKY29sbmFtZXMobWF0cml4LnRvdGFsLmRlbHRhX3N1bXMpIDwtIGMoIk5vbl90ZW1wbGF0ZSIsICJUZW1wbGF0ZSIsICJJRCIpCgoKCm1hdHJpeC50b3RhbC5kZWx0YV9zdW1zIDwtIGRhdGEudGFibGUobWF0cml4LnRvdGFsLmRlbHRhX3N1bXMpCgoKc2V0RFQobWF0cml4LnRvdGFsLmRlbHRhX3N1bXMpWywgYygiRmFjdG9yX0lEIiwgIkNlbGwiLCAiRmlsZSIpIDo9IHRzdHJzcGxpdChJRCwgIl8iKV0KCnNldERUKG1hdHJpeC50b3RhbC5kZWx0YV9zdW1zKVssIGMoIkdlbmUiLCAiU3BlY2llIikgOj0gdHN0cnNwbGl0KEZhY3Rvcl9JRCwgIiIpXQoKCgoKbWF0cml4LnRvdGFsLmRlbHRhX3N1bXMuY29sbGFwc2VkIDwtIG1hdHJpeC50b3RhbC5kZWx0YV9zdW1zWyAsIC4oTm9uX3RlbXBsYXRlLm1lYW49bWVhbihOb25fdGVtcGxhdGUpLCBUZW1wbGF0ZS5tZWFuPW1lYW4oVGVtcGxhdGUpKSAsIGJ5PWMoIkdlbmUiLCAiQ2VsbCIpXQoKbWF0cml4LnRvdGFsLmRlbHRhX3N1bXMua2NsIDwtIG1lcmdlKG1hdHJpeC50b3RhbC5kZWx0YV9zdW1zLmNvbGxhcHNlZCwgaHVtYW5fZGlmZlshaXMubmEoR2VuZSldLCBieT0iR2VuZSIpCmBgYAoKCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTZ9CmdncGxvdCgpICsKZ2VvbV9wb2ludChkYXRhID0gbWF0cml4LnRvdGFsLmRlbHRhX3N1bXMua2NsWyFpcy5uYShHZW5lKV0sIGFlcyggTm9uX3RlbXBsYXRlLm1lYW4sIFRlbXBsYXRlLm1lYW4gICksIGNvbG91cj0iZ3JleSIsIGFscGhhPTAuNSAgKSsKZ2VvbV9wb2ludChkYXRhID0gbWF0cml4LnRvdGFsLmRlbHRhX3N1bXMua2NsW3BhZGo8MC4wNSAmIGxvZzJGb2xkQ2hhbmdlPDAgJiAoYFNwbGljaW5nIHJlZ3VsYXRpb25gPT0xICYgU3BsaWNlb3NvbWU9PTApICwgXSwgYWVzKCBOb25fdGVtcGxhdGUubWVhbiwgVGVtcGxhdGUubWVhbiAgKSAsICBjb2xvdXI9InJlZCIsIGFscGhhPTAuOCAgICkgKwpnZW9tX3BvaW50KGRhdGEgPSBtYXRyaXgudG90YWwuZGVsdGFfc3Vtcy5rY2xbcGFkajwwLjA1ICYgbG9nMkZvbGRDaGFuZ2U+MCAmICAoYFNwbGljaW5nIHJlZ3VsYXRpb25gPT0xICYgU3BsaWNlb3NvbWU9PTApICwgXSwgYWVzKCBOb25fdGVtcGxhdGUubWVhbiwgVGVtcGxhdGUubWVhbiApICwgIGNvbG91cj0iYmx1ZSIsIGFscGhhPTAuOCAgICkgKyAgCiAgCmdlb21fdGV4dF9yZXBlbChkYXRhID0gbWF0cml4LnRvdGFsLmRlbHRhX3N1bXMua2NsW3BhZGo8MC4wNSAmIChgU3BsaWNpbmcgcmVndWxhdGlvbmA9PTEgJiBTcGxpY2Vvc29tZT09MCkgLCBdLAogICAgICAgICAgICAgICAgY29sb3VyPSJibGFjayIsIGFlcyggTm9uX3RlbXBsYXRlLm1lYW4sIFRlbXBsYXRlLm1lYW4sCiAgICAgICAgICAgICAgICBsYWJlbD1tYXRyaXgudG90YWwuZGVsdGFfc3Vtcy5rY2xbcGFkajwwLjA1ICYgKGBTcGxpY2luZyByZWd1bGF0aW9uYD09MSAmIFNwbGljZW9zb21lPT0wKSAgLCBHZW5lXSksCiAgICAgICAgICAgICAgICBmb3JjZSA9IDEuNQogICAgICAgICAgICAgICAgI251ZGdlX3ggICAgICA9IDAuMwogICAgICAgICAgICAgICAgI2RpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICNhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICN2anVzdCAgICAgICAgPSAxLAogICAgICAgICAgICAgICAgI3NlZ21lbnQuc2l6ZSA9IDEsCiAgICAgICAgICAgICAgICAjbGFiZWwuc2l6ZSA9IDAuMDUsCiAgICAgICAgICAgICAgICApICAgKwogIApmYWNldF9ncmlkKENlbGwgfiAuKSArCiN4bGltKGMoLTEsMSkpICsKI3hsYWIoZXhwcmVzc2lvbihsb2dbMl1+Rm9sZH5DaGFuZ2UpKSsKI3lsYWIoZXhwcmVzc2lvbiAobG9nWzEwXX4iQWRqdXN0ZWQgcC12YWx1ZSIpKSsKdGhlbWVfYncoKQpgYGAKCgoKCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9Nn0KZ2dwbG90KCkgKwpnZW9tX3BvaW50KGRhdGEgPSBtYXRyaXgudG90YWwuZGVsdGFfc3Vtcy5rY2xbIWlzLm5hKEdlbmUpXSwgYWVzKCBOb25fdGVtcGxhdGUubWVhbiwgVGVtcGxhdGUubWVhbiAgKSwgY29sb3VyPSJncmV5IiwgYWxwaGE9MC41ICApKwpnZW9tX3BvaW50KGRhdGEgPSBtYXRyaXgudG90YWwuZGVsdGFfc3Vtcy5rY2xbcGFkajwwLjA1ICYgbG9nMkZvbGRDaGFuZ2U8MCAmIChgSGVsaWNhc2VgPT0xKSAsIF0sIGFlcyggTm9uX3RlbXBsYXRlLm1lYW4sIFRlbXBsYXRlLm1lYW4gICkgLCAgY29sb3VyPSJyZWQiLCBhbHBoYT0wLjggICApICsKZ2VvbV9wb2ludChkYXRhID0gbWF0cml4LnRvdGFsLmRlbHRhX3N1bXMua2NsW3BhZGo8MC4wNSAmIGxvZzJGb2xkQ2hhbmdlPjAgJiAgKGBIZWxpY2FzZWA9PTEgKSAsIF0sIGFlcyggTm9uX3RlbXBsYXRlLm1lYW4sIFRlbXBsYXRlLm1lYW4gKSAsICBjb2xvdXI9ImJsdWUiLCBhbHBoYT0wLjggICApICsgIAogIApnZW9tX3RleHRfcmVwZWwoZGF0YSA9IG1hdHJpeC50b3RhbC5kZWx0YV9zdW1zLmtjbFtwYWRqPDAuMDUgJiAoYEhlbGljYXNlYD09MSApICwgXSwKICAgICAgICAgICAgICAgIGNvbG91cj0iYmxhY2siLCBhZXMoIE5vbl90ZW1wbGF0ZS5tZWFuLCBUZW1wbGF0ZS5tZWFuLAogICAgICAgICAgICAgICAgbGFiZWw9bWF0cml4LnRvdGFsLmRlbHRhX3N1bXMua2NsW3BhZGo8MC4wNSAmIChgSGVsaWNhc2VgPT0xICkgICwgR2VuZV0pLAogICAgICAgICAgICAgICAgZm9yY2UgPSAxLjUKICAgICAgICAgICAgICAgICNudWRnZV94ICAgICAgPSAwLjMKICAgICAgICAgICAgICAgICNkaXJlY3Rpb24gICAgPSAieCIsCiAgICAgICAgICAgICAgICAjYW5nbGUgICAgICAgID0gOTAsCiAgICAgICAgICAgICAgICAjdmp1c3QgICAgICAgID0gMSwKICAgICAgICAgICAgICAgICNzZWdtZW50LnNpemUgPSAxLAogICAgICAgICAgICAgICAgI2xhYmVsLnNpemUgPSAwLjA1LAogICAgICAgICAgICAgICAgKSAgICsKICAKZmFjZXRfZ3JpZChDZWxsIH4gLikgKwojeGxpbShjKC0xLDEpKSArCnhsYWIoZXhwcmVzc2lvbihsb2dbMl1+Rm9sZH5DaGFuZ2UpKSsKeWxhYihleHByZXNzaW9uIChsb2dbMTBdfiJBZGp1c3RlZCBwLXZhbHVlIikpKwp0aGVtZV9idygpCgpgYGAKIyMjIyMKCgoKCgoKCgpgYGB7cn0KCgoKcmVhZF9kaXN0X3RhYmxlIDwtIGZ1bmN0aW9uKHBhdGgpewogIApkaXN0X3RhYmxlIDwtIGRhdGEudGFibGUocmVhZF9kZWxpbShwYXRoLCAKICAgICJcdCIsIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwgY29sX25hbWVzID0gRkFMU0UsIAogICAgdHJpbV93cyA9IFRSVUUpKQoKZGlzdF90YWJsZSA8LSBkaXN0X3RhYmxlWywgMjoyMDAxXQpkaXN0X3RhYmxlIDwtIGRhdGEudGFibGUoYXMuZGF0YS5mcmFtZSh0KGRpc3RfdGFibGUpKSkKY29sbmFtZXMoZGlzdF90YWJsZSkgPC0gYygiUG9zaXRpb24iLCAiT2NjdXJyZW5jZXMiKQoKZGlzdF90YWJsZVssbWVkaWFuOj1tZWRpYW4oT2NjdXJyZW5jZXMpXQpkaXN0X3RhYmxlWywgRW5ycmljaG1lbnQ6PU9jY3VycmVuY2VzL21lZGlhbl0KZGlzdF90YWJsZVssIFBvc2l0aW9uOj1Qb3NpdGlvbi0xXQoKcmV0dXJuKGRpc3RfdGFibGUpICAKfQoKCmBgYAoKCgpgYGB7cn0KCgpwbG90X2RlbnNpdHlfYmlub21pYWxfUkJQIDwtIGZ1bmN0aW9uKHVwX3BsdXMsIHVwX21pbnVzLCBkb3duX3BsdXMsIGRvd25fbWludXMsIG9ic2VydmF0aW9uc191cCwgb2JzZXJ2YXRpb25zX2Rvd24sIHNpZyl7CgogIAogIHVwX1RPVEFMIDwtICBtZXJnZSh1cF9wbHVzLCB1cF9taW51cywgYnk9IlBvc2l0aW9uIikKICB1cF9UT1RBTFssT2NjdXJyZW5jZXM6PU9jY3VycmVuY2VzLngrT2NjdXJyZW5jZXMueV0KICB1cF9UT1RBTFssT2NjdXJyZW5jZXM6PU9jY3VycmVuY2VzLngrT2NjdXJyZW5jZXMueV0KICAKCiAgCiAgCiAgdXBfVE9UQUwgPC0gY2JpbmQodXBfVE9UQUwsIHVwX1RPVEFMWywgYmluY29uZihPY2N1cnJlbmNlcywgb2JzZXJ2YXRpb25zX3VwLCBhbHBoYT1zaWcpIF0pCgogIHVwX1RPVEFMWyxtZWRpYW46PW1lZGlhbihQb2ludEVzdCldCiAgdXBfVE9UQUxbLCBFbnJyaWNobWVudDo9UG9pbnRFc3QvbWVkaWFuXQogIHVwX1RPVEFMWywgRW5ycmljaG1lbnRfbDo9TG93ZXIvbWVkaWFuXQogIHVwX1RPVEFMWywgRW5ycmljaG1lbnRfdTo9VXBwZXIvbWVkaWFuXQogIHVwX1RPVEFMWywgUG9zaXRpb246PVBvc2l0aW9uLTFdCgogIAogIAogIGRvd25fVE9UQUwgPC0gIG1lcmdlKGRvd25fcGx1cywgZG93bl9taW51cywgYnk9IlBvc2l0aW9uIikKICBkb3duX1RPVEFMWyxPY2N1cnJlbmNlczo9T2NjdXJyZW5jZXMueCtPY2N1cnJlbmNlcy55XQoKICAKICBkb3duX1RPVEFMIDwtIGNiaW5kKGRvd25fVE9UQUwsIGRvd25fVE9UQUxbLCBiaW5jb25mKE9jY3VycmVuY2VzLCBvYnNlcnZhdGlvbnNfZG93biwgYWxwaGE9c2lnKSBdKQoKICBkb3duX1RPVEFMWyxtZWRpYW46PW1lZGlhbihQb2ludEVzdCldCiAgZG93bl9UT1RBTFssIEVucnJpY2htZW50Oj1Qb2ludEVzdC9tZWRpYW5dCiAgZG93bl9UT1RBTFssIEVucnJpY2htZW50X2w6PUxvd2VyL21lZGlhbl0KICBkb3duX1RPVEFMWywgRW5ycmljaG1lbnRfdTo9VXBwZXIvbWVkaWFuXQogIGRvd25fVE9UQUxbLCBQb3NpdGlvbjo9UG9zaXRpb24tMV0gIAogIAogIAogIHVwX1RPVEFMWyAsZXhvbl9wb3M6PSJVcHN0cmVhbSJdCiAgZG93bl9UT1RBTFsgLGV4b25fcG9zOj0iRG93bnN0cmVhbSJdCiAgCiAgVE9UQUwgPC0gcmJpbmQodXBfVE9UQUwsIGRvd25fVE9UQUwpCiAgCiAgVE9UQUwkZXhvbl9wb3MgPC0gIGZhY3RvcihUT1RBTCRleG9uX3BvcywgbGV2ZWxzPWMoIlVwc3RyZWFtIiwgIkRvd25zdHJlYW0iICkpIAogIAogIHAgPC0gZ2dwbG90KFRPVEFMKSsKICAgIGdlb21fbGluZShhZXMoeD1Qb3NpdGlvbix5PUVucnJpY2htZW50KSkgKwogICAgZ2VvbV9yaWJib24oYWVzKHltaW49RW5ycmljaG1lbnRfbCwgeW1heD1FbnJyaWNobWVudF91LCB4PVBvc2l0aW9uKSwgYWxwaGE9MC4zICkrCiAgICBmYWNldF9ncmlkKCAuIH4gZXhvbl9wb3MgKSArCiAgICB0aGVtZV9idygpCiAgCiAgI3Nob3cocCkKICAKICByZXR1cm4oVE9UQUwpIAogIAp9CmBgYAoKCgpgYGB7cn0KcGxvdF9lcWxfZGlmZl9iaW5vbWlhbF90YWJsZSA8LSBmdW5jdGlvbihlcWxfdXBfcGx1cywgZXFsX3VwX21pbnVzLCBlcWxfZG93bl9wbHVzLCBlcWxfZG93bl9taW51cywgZGlmZl91cF9wbHVzLCBkaWZmX3VwX21pbnVzLCBkaWZmX2Rvd25fcGx1cywgZGlmZl9kb3duX21pbnVzLCBUT1RBTC5lcWxfdXAsIFRPVEFMLmVxbF9kb3duLCBUT1RBTC5kaWZmX3VwLCBUT1RBTC5kaWZmX2Rvd24sIHNpZyAgICl7IAoKCmRpZmYudXBfcGx1cyA8LSByZWFkX2Rpc3RfdGFibGUoZGlmZl91cF9wbHVzKQpkaWZmLnVwX21pbnVzIDwtIHJlYWRfZGlzdF90YWJsZShkaWZmX3VwX21pbnVzKQpkaWZmLmRvd25fcGx1cyA8LSByZWFkX2Rpc3RfdGFibGUoZGlmZl9kb3duX3BsdXMpCmRpZmYuZG93bl9taW51cyA8LSByZWFkX2Rpc3RfdGFibGUoZGlmZl9kb3duX21pbnVzKQpkaWZmLnVwX21pbnVzWyxQb3NpdGlvbjo9UG9zaXRpb24qLTFdCmRpZmYuZG93bl9taW51c1ssUG9zaXRpb246PVBvc2l0aW9uKi0xXQoKCmRpZmYuVE9UQUwgPC0gcGxvdF9kZW5zaXR5X2Jpbm9taWFsX1JCUChkaWZmLnVwX3BsdXMsIGRpZmYudXBfbWludXMsIGRpZmYuZG93bl9wbHVzLCBkaWZmLmRvd25fbWludXMsIFRPVEFMLmRpZmZfdXAsIFRPVEFMLmRpZmZfZG93biwgc2lnKQoKCmVxbC51cF9wbHVzIDwtIHJlYWRfZGlzdF90YWJsZShlcWxfdXBfcGx1cykKZXFsLnVwX21pbnVzIDwtIHJlYWRfZGlzdF90YWJsZShlcWxfdXBfbWludXMpCmVxbC5kb3duX3BsdXMgPC0gcmVhZF9kaXN0X3RhYmxlKGVxbF9kb3duX3BsdXMpCmVxbC5kb3duX21pbnVzIDwtIHJlYWRfZGlzdF90YWJsZShlcWxfZG93bl9taW51cykKZXFsLnVwX21pbnVzWyxQb3NpdGlvbjo9UG9zaXRpb24qLTFdCmVxbC5kb3duX21pbnVzWyxQb3NpdGlvbjo9UG9zaXRpb24qLTFdCgoKZXFsLlRPVEFMIDwtIHBsb3RfZGVuc2l0eV9iaW5vbWlhbF9SQlAoZXFsLnVwX3BsdXMsIGVxbC51cF9taW51cywgZXFsLmRvd25fcGx1cywgZXFsLmRvd25fbWludXMsIFRPVEFMLmVxbF91cCwgVE9UQUwuZXFsX2Rvd24sIHNpZykKCmRpZmYuVE9UQUxbLCB0eXBlOj0id0c0Il0KZXFsLlRPVEFMWywgdHlwZTo9IndvRzQiXQoKZGlmZl9lcWwuVE9UQUwgPC0gcmJpbmQoZGlmZi5UT1RBTCwgZXFsLlRPVEFMKQoKcmV0dXJuKGRpZmZfZXFsLlRPVEFMKQoKfQpgYGAKCgpgYGB7cn0KCgoKZmlsZXMgPC0gbGlzdC5maWxlcygiLi9SQlBzLyIsIHBhdHRlcm4gPSJleG9uLmRvd25fbWludXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fbWludXNfc3RyYW5kLndHNC5zY29yZS4iKQoKc2FtcGxlcyA8LSBzdHJfcmVwbGFjZShzdHJfcmVwbGFjZShmaWxlcywgICJleG9uLmRvd25fbWludXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fbWludXNfc3RyYW5kLndHNC5zY29yZS4iLCAiIiApLCAiLmJlZC5saXN0Lm91dC5udW0iLCAiIikKCm1ldGFkYXRhIDwtIGZyZWFkKCIuL1JCUHMvbWV0YWRhdGEudHN2IikKI3NhbXBsZSA9ICdFTkNGRjc4NkpBTScKCgpgYGAKCgpgYGB7cn0KZmlndXJlNl9zYW1wbGVzIDwtIGMoIkVOQ0ZGNDY1UUtTIiwgIkVOQ0ZGNDA0T1NLIiwgIkVOQ0ZGODc3S0JKIiwgIkVOQ0ZGMDE0QlhWIiwgIkVOQ0ZGNjM5TVlJIikKYGBgCgoKYGBge3J9CmZpZ3VyZTZfc2FtcGxlcwpgYGAKCmBgYHtyfQp1bmlxdWUoZmlndXJlNl90YWJsZSRJRCkKYGBgCgoKYGBge3J9CmZpZ3VyZTZfc2FtcGxlcyAlaW4lIHVuaXF1ZShmaWd1cmU2X3RhYmxlJElEKQpgYGAKCgojIyMjIyBSZWJ1dHRhbAoKYGBge3IsIGZpZy53aWR0aD0gMTAgLCBmaWcuaGVpZ2h0PTV9CgoKZmlndXJlNl90YWJsZSA8LSBkYXRhLnRhYmxlKCkKCmZvciAoc2FtcGxlIGluIGZpZ3VyZTZfc2FtcGxlcyl7CiAgCiAgaWYgKGxlbmd0aCggbGlzdC5maWxlcygiLi9SQlBzLyIsIHBhdHRlcm4gPSBzYW1wbGUpKT49MTYpewoKICBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlIDwtIHBsb3RfZXFsX2RpZmZfYmlub21pYWxfdGFibGUoCiAgcGFzdGUoIi4vUkJQcy9leG9uLnVwX3BsdXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fcGx1c19zdHJhbmQud29HNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgcGFzdGUoIi4vUkJQcy9leG9uLnVwX21pbnVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX21pbnVzX3N0cmFuZC53b0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICBwYXN0ZSgiLi9SQlBzL2V4b24uZG93bl9wbHVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX3BsdXNfc3RyYW5kLndvRzQuc2NvcmUuIiwgc2FtcGxlLCAiLmJlZC5saXN0Lm91dC5udW0iLCBzZXA9IiIpLAogIHBhc3RlKCIuL1JCUHMvZXhvbi5kb3duX21pbnVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX21pbnVzX3N0cmFuZC53b0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICBwYXN0ZSgiLi9SQlBzL2V4b24udXBfcGx1cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9wbHVzX3N0cmFuZC53RzQuc2NvcmUuIiwgc2FtcGxlLCAiLmJlZC5saXN0Lm91dC5udW0iLCBzZXA9IiIpLAogIHBhc3RlKCIuL1JCUHMvZXhvbi51cF9taW51cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9taW51c19zdHJhbmQud0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICBwYXN0ZSgiLi9SQlBzL2V4b24uZG93bl9wbHVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX3BsdXNfc3RyYW5kLndHNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgcGFzdGUoIi4vUkJQcy9leG9uLmRvd25fbWludXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fbWludXNfc3RyYW5kLndHNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgMTEwODcwICsgMTA5NDY3LAogIDEwODYzOCArIDEwNzQzMywKICAzNTg3ICsgMzQzMSwKICA1ODE5ICsgNTQ2NSwKICAwLjA1CiAgKQogIAogIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGUkcG9zX2ludCA8LSBjdXQoUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZSRQb3NpdGlvbiwgYnJlYWtzID0gNDAsIGxhYmVscyA9IHNlcSgtOTk5LDEwMDAsNTApLTEpCiAgUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZV9zdGF0cyA8LSBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlWyAsIC4oRW5ycmljaG1lbnQ9bWVhbihFbnJyaWNobWVudCksIEVucnJpY2htZW50X2w9bWVhbihFbnJyaWNobWVudF9sKSwgRW5ycmljaG1lbnRfdT1tZWFuKEVucnJpY2htZW50X3UpKSAgLCBieT1jKCAiZXhvbl9wb3MiLCAidHlwZSIsICAicG9zX2ludCIgICkgXQogIAogIAogIFRvdGFsLk92ZXJsYXBzLm5vbl90ZW1wbGF0ZSA8LSBjKCkKICAKICBmb3IgKGkgaW4gc2VxKC0yMDAsIDIwMCwgNTApKXsKICAKICBPLlVwc3RyZWFtIDwtIE92ZXJsYXAoCiAgUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZV9zdGF0c1sgZXhvbl9wb3M9PSJVcHN0cmVhbSIgJiBwb3NfaW50PT1pICYgdHlwZT09IndHNCIsIGMoIkVucnJpY2htZW50X2wiLCAiRW5ycmljaG1lbnRfdSIpXSwKICBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlX3N0YXRzWyBleG9uX3Bvcz09IlVwc3RyZWFtIiAmIHBvc19pbnQ9PWkgJiB0eXBlPT0id29HNCIsIGMoIkVucnJpY2htZW50X2wiLCAiRW5ycmljaG1lbnRfdSIpXQogICkKICAKICBPLkRvd25zdHJlYW0gPC0gT3ZlcmxhcCgKICBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlX3N0YXRzWyBleG9uX3Bvcz09IkRvd25zdHJlYW0iICYgcG9zX2ludD09aSAmIHR5cGU9PSJ3RzQiLCBjKCJFbnJyaWNobWVudF9sIiwgIkVucnJpY2htZW50X3UiKV0sCiAgUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZV9zdGF0c1sgZXhvbl9wb3M9PSJEb3duc3RyZWFtIiAmIHBvc19pbnQ9PWkgJiB0eXBlPT0id29HNCIsIGMoIkVucnJpY2htZW50X2wiLCAiRW5ycmljaG1lbnRfdSIpXQogICkKICAKICBUb3RhbC5PdmVybGFwcy5ub25fdGVtcGxhdGUgPC0gcmJpbmQoVG90YWwuT3ZlcmxhcHMubm9uX3RlbXBsYXRlLCBjKE8uVXBzdHJlYW0sIE8uRG93bnN0cmVhbSkpCiAgCiAgfQogIAogIAogIFJCUF9iaW5vbWlhbF90YWJsZV90ZW1wbGF0ZSA8LSBwbG90X2VxbF9kaWZmX2Jpbm9taWFsX3RhYmxlKAogIHBhc3RlKCIuL1JCUHMvZXhvbi51cF9wbHVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX21pbnVzX3N0cmFuZC53b0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICBwYXN0ZSgiLi9SQlBzL2V4b24udXBfbWludXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fcGx1c19zdHJhbmQud29HNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgcGFzdGUoIi4vUkJQcy9leG9uLmRvd25fcGx1cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9taW51c19zdHJhbmQud29HNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgcGFzdGUoIi4vUkJQcy9leG9uLmRvd25fbWludXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fcGx1c19zdHJhbmQud29HNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgcGFzdGUoIi4vUkJQcy9leG9uLnVwX3BsdXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fbWludXNfc3RyYW5kLndHNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgcGFzdGUoIi4vUkJQcy9leG9uLnVwX21pbnVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX3BsdXNfc3RyYW5kLndHNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgcGFzdGUoIi4vUkJQcy9leG9uLmRvd25fcGx1cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9taW51c19zdHJhbmQud0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICBwYXN0ZSgiLi9SQlBzL2V4b24uZG93bl9taW51cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9wbHVzX3N0cmFuZC53RzQuc2NvcmUuIiwgc2FtcGxlLCAiLmJlZC5saXN0Lm91dC5udW0iLCBzZXA9IiIpLAogIDExMDg0MSArIDEwOTUwNCwKICAxMTE1MDggKyAxMTAwMjUsCiAgMzYxNiArIDMzOTQsCiAgMjk0OSArIDI4NzMsCiAgMC4wNQogICkKICAKICAKICAKICBSQlBfYmlub21pYWxfdGFibGVfdGVtcGxhdGUkcG9zX2ludCA8LSBjdXQoUkJQX2Jpbm9taWFsX3RhYmxlX3RlbXBsYXRlJFBvc2l0aW9uLCBicmVha3MgPSA0MCwgbGFiZWxzID0gc2VxKC05OTksMTAwMCw1MCktMSkKICBSQlBfYmlub21pYWxfdGFibGVfdGVtcGxhdGVfc3RhdHMgPC0gUkJQX2Jpbm9taWFsX3RhYmxlX3RlbXBsYXRlWyAsIC4oRW5ycmljaG1lbnQ9bWVhbihFbnJyaWNobWVudCksIEVucnJpY2htZW50X2w9bWVhbihFbnJyaWNobWVudF9sKSwgRW5ycmljaG1lbnRfdT1tZWFuKEVucnJpY2htZW50X3UpKSAgLCBieT1jKCAiZXhvbl9wb3MiLCAidHlwZSIsICAicG9zX2ludCIgICkgXQogIAogIAogIFRvdGFsLk92ZXJsYXBzLnRlbXBsYXRlIDwtIGMoKQogIAogIGZvciAoaSBpbiBzZXEoLTIwMCwgMjAwLCA1MCkpewogIAogIE8uVXBzdHJlYW0gPC0gT3ZlcmxhcCgKICBSQlBfYmlub21pYWxfdGFibGVfdGVtcGxhdGVfc3RhdHNbIGV4b25fcG9zPT0iVXBzdHJlYW0iICYgcG9zX2ludD09aSAmIHR5cGU9PSJ3RzQiLCBjKCJFbnJyaWNobWVudF9sIiwgIkVucnJpY2htZW50X3UiKV0sCiAgUkJQX2Jpbm9taWFsX3RhYmxlX3RlbXBsYXRlX3N0YXRzWyBleG9uX3Bvcz09IlVwc3RyZWFtIiAmIHBvc19pbnQ9PWkgJiB0eXBlPT0id29HNCIsIGMoIkVucnJpY2htZW50X2wiLCAiRW5ycmljaG1lbnRfdSIpXQogICkKICAKICBPLkRvd25zdHJlYW0gPC0gT3ZlcmxhcCgKICBSQlBfYmlub21pYWxfdGFibGVfdGVtcGxhdGVfc3RhdHNbIGV4b25fcG9zPT0iRG93bnN0cmVhbSIgJiBwb3NfaW50PT1pICYgdHlwZT09IndHNCIsIGMoIkVucnJpY2htZW50X2wiLCAiRW5ycmljaG1lbnRfdSIpXSwKICBSQlBfYmlub21pYWxfdGFibGVfdGVtcGxhdGVfc3RhdHNbIGV4b25fcG9zPT0iRG93bnN0cmVhbSIgJiBwb3NfaW50PT1pICYgdHlwZT09IndvRzQiLCBjKCJFbnJyaWNobWVudF9sIiwgIkVucnJpY2htZW50X3UiKV0KICApCiAgCiAgVG90YWwuT3ZlcmxhcHMudGVtcGxhdGUgPC0gcmJpbmQoVG90YWwuT3ZlcmxhcHMudGVtcGxhdGUsIGMoTy5VcHN0cmVhbSwgTy5Eb3duc3RyZWFtKSkKICAKICB9CiAgCiAgCiAgCiAgCiAgaWYgKDAgJWluJSByYmluZChUb3RhbC5PdmVybGFwcy5ub25fdGVtcGxhdGUsICBUb3RhbC5PdmVybGFwcy50ZW1wbGF0ZSkgKXsKICAgIAogICAgCiAgICBoZWFkKFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGUpCiAgICAKICAgIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGVbLCBETkFfc2Vuc2U6PSJub25fdGVtcGxhdGUiXQogICAgUkJQX2Jpbm9taWFsX3RhYmxlX3RlbXBsYXRlWywgRE5BX3NlbnNlOj0idGVtcGxhdGUiXQogICAgCiAgICBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlWywgSUQ6PXNhbXBsZV0KICAgIFJCUF9iaW5vbWlhbF90YWJsZV90ZW1wbGF0ZVssIElEOj1zYW1wbGVdCiAgICAKICAgIGZpZ3VyZTZfdGFibGUgPC0gcmJpbmQoZmlndXJlNl90YWJsZSwgUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZSkKICAgIGZpZ3VyZTZfdGFibGUgPC0gcmJpbmQoZmlndXJlNl90YWJsZSwgUkJQX2Jpbm9taWFsX3RhYmxlX3RlbXBsYXRlKQogICAgCiAgICAgICAKIyAgICBSQlBfcGxvdC5ub25fdGVtcGxhdGUgPC0gZ2dwbG90KFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGUpICsKIyAgICBnZW9tX2xpbmUoYWVzKHg9UG9zaXRpb24sIHk9RW5ycmljaG1lbnQsIGNvbG9yPXR5cGUpKSArCiMgICAgIGdlb21fcmliYm9uKGFlcyh5bWluPUVucnJpY2htZW50X2wsIHltYXg9RW5ycmljaG1lbnRfdSwgeD1Qb3NpdGlvbiwgZmlsbD10eXBlKSwgYWxwaGE9MC4zICkrCiMgICAgeGxpbShjKC0yNTAsMjUwKSkgKwojICAgIGZhY2V0X2dyaWQoLiB+IGV4b25fcG9zICApICsKIyAgICBsYWJzKGNvbG91ciA9ICIxMDBudCBmbGFua2luZyBpbnRyb25pYyB3aW5kb3ciLCBmaWxsPSIxMDBudCBmbGFua2luZyBpbnRyb25pYyB3aW5kb3ciKSArCiMgICAgdGhlbWVfYncoKSArCiMgICAgZ2d0aXRsZShwYXN0ZShtZXRhZGF0YVtgRmlsZSBhY2Nlc3Npb25gPT1zYW1wbGUsIGBFeHBlcmltZW50IHRhcmdldGBdLCBtZXRhZGF0YVtgRmlsZSBhY2Nlc3Npb25gPT1zYW1wbGUsIGBCaW9zYW1wbGUgdGVybSBuYW1lYF0sIHNhbXBsZSwgIm5vbi10ZW1wbGF0ZSIpKSArCiMgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpICsKIyAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzY2OTkwMCIsICJncmV5IikpICsgIAojICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzY2OTkwMCIsICJkYXJrZ3JleSIpKQogICAgCiAgICAKIyAgICBSQlBfcGxvdC50ZW1wbGF0ZSA8LSAgZ2dwbG90KFJCUF9iaW5vbWlhbF90YWJsZV90ZW1wbGF0ZSkgKwojICAgIGdlb21fbGluZShhZXMoeD1Qb3NpdGlvbiwgeT1FbnJyaWNobWVudCwgY29sb3I9dHlwZSkpICsKIyAgICAgZ2VvbV9yaWJib24oYWVzKHltaW49RW5ycmljaG1lbnRfbCwgeW1heD1FbnJyaWNobWVudF91LCB4PVBvc2l0aW9uLCBmaWxsPXR5cGUpLCBhbHBoYT0wLjMgKSsKIyAgICB4bGltKGMoLTI1MCwyNTApKSArCiMgICAgZmFjZXRfZ3JpZCguIH4gZXhvbl9wb3MgICkgKwojICAgIGxhYnMoY29sb3VyID0gIjEwMG50IGZsYW5raW5nIGludHJvbmljIHdpbmRvdyIsIGZpbGw9IjEwMG50IGZsYW5raW5nIGludHJvbmljIHdpbmRvdyIpICsKIyAgICB0aGVtZV9idygpICsKIyAgICBnZ3RpdGxlKHBhc3RlKG1ldGFkYXRhW2BGaWxlIGFjY2Vzc2lvbmA9PXNhbXBsZSwgYEV4cGVyaW1lbnQgdGFyZ2V0YCBdLCBtZXRhZGF0YVtgRmlsZSBhY2Nlc3Npb25gPT1zYW1wbGUsIGBCaW9zYW1wbGUgdGVybSBuYW1lYF0sICBzYW1wbGUsICJ0ZW1wbGF0ZSIpKSArCiMgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpICsKIyAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzY2OTkwMCIsICJncmV5IikpICsgIAojICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzY2OTkwMCIsICJkYXJrZ3JleSIpKQogICAgCiAgICAKIyAgICBwZGYocGFzdGUwKCIuL1JCUHMvcGxvdHMvIiwgc2FtcGxlICwgIi5wZGYiKSkgCiMgICAgcGxvdF9ncmlkKFJCUF9wbG90Lm5vbl90ZW1wbGF0ZSwgUkJQX3Bsb3QudGVtcGxhdGUsICBucm93ID0xKQojICAgIGRldi5vZmYoKSAKICAgIAogIH0KICAKICB9CgoKfQpgYGAKCmBgYHtyfQpmaWd1cmU2X3RhYmxlWyAsIC4oZXhvbl9wb3MsIEROQV9zZW5zZSldCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9Ni41fQoKCiAgICAKZmlndXJlNl90YWJsZVsgLCBjb2xfcG9zOj1wYXN0ZShleG9uX3BvcywgRE5BX3NlbnNlKV0KCmZpZ3VyZTZfdGFibGUkY29sX3BvcyA8LSBmYWN0b3IoZmlndXJlNl90YWJsZSRjb2xfcG9zLCBsZXZlbHMgPSBjKCdVcHN0cmVhbSBub25fdGVtcGxhdGUnICwgJ0Rvd25zdHJlYW0gbm9uX3RlbXBsYXRlJywgICdVcHN0cmVhbSB0ZW1wbGF0ZScsICdEb3duc3RyZWFtIHRlbXBsYXRlJykpCgpmaWd1cmU2X3RhYmxlJElEIDwtIGZhY3RvcihmaWd1cmU2X3RhYmxlJElELCBsZXZlbHMgPSBmaWd1cmU2X3NhbXBsZXMpCgogZ2dwbG90KGZpZ3VyZTZfdGFibGUpICsKICAgIGdlb21fbGluZShhZXMoeD1Qb3NpdGlvbiwgeT1FbnJyaWNobWVudCwgY29sb3I9dHlwZSkpICsKICAgICBnZW9tX3JpYmJvbihhZXMoeW1pbj1FbnJyaWNobWVudF9sLCB5bWF4PUVucnJpY2htZW50X3UsIHg9UG9zaXRpb24sIGZpbGw9dHlwZSksIGFscGhhPTAuMyApKwogICAgeGxpbShjKC0yNTAsMjUwKSkgKwogICAgZmFjZXRfZ3JpZChJRCB+IGNvbF9wb3MsIHNjYWxlcz0iZnJlZV95IiAgKSArCiAgICBsYWJzKGNvbG91ciA9ICIxMDBudCBmbGFua2luZyBpbnRyb25pYyB3aW5kb3ciLCBmaWxsPSIxMDBudCBmbGFua2luZyBpbnRyb25pYyB3aW5kb3ciKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzY2OTkwMCIsICJncmV5IikpICsgIAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjNjY5OTAwIiwgImRhcmtncmV5IikpICsKICAgI3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgdmp1c3QgPSAwLjUpKQogICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1KSkKYGBgCgoKCmBgYHtyfQoKZGVsdGEubm9uX3RlbXBsYXRlLnJvd3MgPC0gYygpCm1hdHJpeC5ub25fdGVtcGxhdGUucm93X25hbWVzIDwtIGMoKQptYXRyaXgubm9uX3RlbXBsYXRlIDwtIGMoKQoKc2FtcGxlID0iRU5DRkY2MzlNWUkiCiNmb3IgKHNhbXBsZSBpbiBzYW1wbGVzKXsKICAKIyAgaWYgKGxlbmd0aCggbGlzdC5maWxlcygiLi9SQlBzLyIsIHBhdHRlcm4gPSBzYW1wbGUpKT09MTYgJiAobWV0YWRhdGFbYEZpbGUgYWNjZXNzaW9uYD09c2FtcGxlLCBBc3NlbWJseV09PSJoZzE5IiApICl7CgogIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGUgPC0gcGxvdF9lcWxfZGlmZl9iaW5vbWlhbF90YWJsZSgKICBwYXN0ZSgiLi9SQlBzL2V4b24udXBfcGx1cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9wbHVzX3N0cmFuZC53b0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICBwYXN0ZSgiLi9SQlBzL2V4b24udXBfbWludXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fbWludXNfc3RyYW5kLndvRzQuc2NvcmUuIiwgc2FtcGxlLCAiLmJlZC5saXN0Lm91dC5udW0iLCBzZXA9IiIpLAogIHBhc3RlKCIuL1JCUHMvZXhvbi5kb3duX3BsdXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fcGx1c19zdHJhbmQud29HNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgcGFzdGUoIi4vUkJQcy9leG9uLmRvd25fbWludXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fbWludXNfc3RyYW5kLndvRzQuc2NvcmUuIiwgc2FtcGxlLCAiLmJlZC5saXN0Lm91dC5udW0iLCBzZXA9IiIpLAogIHBhc3RlKCIuL1JCUHMvZXhvbi51cF9wbHVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX3BsdXNfc3RyYW5kLndHNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgcGFzdGUoIi4vUkJQcy9leG9uLnVwX21pbnVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX21pbnVzX3N0cmFuZC53RzQuc2NvcmUuIiwgc2FtcGxlLCAiLmJlZC5saXN0Lm91dC5udW0iLCBzZXA9IiIpLAogIHBhc3RlKCIuL1JCUHMvZXhvbi5kb3duX3BsdXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fcGx1c19zdHJhbmQud0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICBwYXN0ZSgiLi9SQlBzL2V4b24uZG93bl9taW51cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9taW51c19zdHJhbmQud0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICAxMTA4NzAgKyAxMDk0NjcsCiAgMTA4NjM4ICsgMTA3NDMzLAogIDM1ODcgKyAzNDMxLAogIDU4MTkgKyA1NDY1LAogIDAuMDUKICApCgogIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGUkcG9zX2ludCA8LSBjdXQoUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZSRQb3NpdGlvbiwgYnJlYWtzID0gMjAwLCBsYWJlbHMgPSBzZXEoLTk5OSwxMDAwLDEwKS0xKQogIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGVfc3RhdHMgPC0gUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZVsgLCAuKEVucnJpY2htZW50PW1lYW4oRW5ycmljaG1lbnQpLCBFbnJyaWNobWVudF9sPW1lYW4oRW5ycmljaG1lbnRfbCksICAgRW5ycmljaG1lbnRfdT1tZWFuKEVucnJpY2htZW50X3UpKSAgLCBieT1jKCAiZXhvbl9wb3MiLCAidHlwZSIsICAicG9zX2ludCIgICkgXQogIAogIAogIFRvdGFsLmRlbHRhcy5ub25fdGVtcGxhdGUudXAgPC0gYygpCiAgVG90YWwuZGVsdGFzLm5vbl90ZW1wbGF0ZS5kb3duIDwtIGMoKQogIAogICAgZm9yIChpIGluIHNlcSgtMjAwLCAxOTAsIDEwKSl7CiAgICAKICAgIE8uVXBzdHJlYW0gPC0gT3ZlcmxhcCgKICAgIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGVfc3RhdHNbIGV4b25fcG9zPT0iVXBzdHJlYW0iICYgcG9zX2ludD09aSAmIHR5cGU9PSJ3RzQiLCBjKCJFbnJyaWNobWVudF9sIiwgIkVucnJpY2htZW50X3UiKV0sCiAgICBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlX3N0YXRzWyBleG9uX3Bvcz09IlVwc3RyZWFtIiAmIHBvc19pbnQ9PWkgJiB0eXBlPT0id29HNCIsIGMoIkVucnJpY2htZW50X2wiLCAiRW5ycmljaG1lbnRfdSIpXQogICAgKQogICAgCiAgICBpZiAoaXMubmEoTy5VcHN0cmVhbSkpewogICAgICAKICAgICAgTy5VcHN0cmVhbSA8LSAxCiAgICB9CiAgICAKICAgIE8uRG93bnN0cmVhbSA8LSBPdmVybGFwKAogICAgUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZV9zdGF0c1sgZXhvbl9wb3M9PSJEb3duc3RyZWFtIiAmIHBvc19pbnQ9PWkgJiB0eXBlPT0id0c0IiwgYygiRW5ycmljaG1lbnRfbCIsICJFbnJyaWNobWVudF91IildLAogICAgUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZV9zdGF0c1sgZXhvbl9wb3M9PSJEb3duc3RyZWFtIiAmIHBvc19pbnQ9PWkgJiB0eXBlPT0id29HNCIsIGMoIkVucnJpY2htZW50X2wiLCAiRW5ycmljaG1lbnRfdSIpXQogICAgKQogICAgCiAgICBpZiAoaXMubmEoTy5Eb3duc3RyZWFtKSl7CiAgICAgIAogICAgICBPLkRvd25zdHJlYW0gPC0gMQogICB9ICAgIAogICAgCiAgICBkZWx0YS51cCA8LSAwCiAgICAKICAgIGlmIChPLlVwc3RyZWFtPT0wICkgewogICAgICAKICAgICAgZGVsdGEudXAgPC0gUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZV9zdGF0c1sgZXhvbl9wb3M9PSJVcHN0cmVhbSIgJiBwb3NfaW50PT1pICYgdHlwZT09IndHNCIsICJFbnJyaWNobWVudCJdIC0gUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZV9zdGF0c1sgZXhvbl9wb3M9PSJVcHN0cmVhbSIgJiBwb3NfaW50PT1pICYgdHlwZT09IndvRzQiLCAiRW5ycmljaG1lbnQiXQogICAgICAKICAgICAgCiAgICB9CiAgICAgIAogICAgICAKICAgIGRlbHRhLmRvd24gPC0gMAogICAgCiAgICBpZiAoTy5Eb3duc3RyZWFtPT0wICkgewogICAgICAKICAgICAgZGVsdGEuZG93biA8LSBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlX3N0YXRzWyBleG9uX3Bvcz09IkRvd25zdHJlYW0iICYgcG9zX2ludD09aSAmIHR5cGU9PSJ3RzQiLCAiRW5ycmljaG1lbnQiXSAtIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGVfc3RhdHNbIGV4b25fcG9zPT0iRG93bnN0cmVhbSIgJiBwb3NfaW50PT1pICYgdHlwZT09IndvRzQiLCAiRW5ycmljaG1lbnQiXQogICAgICAKICAgICAgCiAgICB9CiAgICAgICAgCiAgICBUb3RhbC5kZWx0YXMubm9uX3RlbXBsYXRlLnVwIDwtIGMoVG90YWwuZGVsdGFzLm5vbl90ZW1wbGF0ZS51cCwgYXMubnVtZXJpYyhkZWx0YS51cCkpCiAgICBUb3RhbC5kZWx0YXMubm9uX3RlbXBsYXRlLmRvd24gPC0gYyhUb3RhbC5kZWx0YXMubm9uX3RlbXBsYXRlLmRvd24sIGFzLm51bWVyaWMoZGVsdGEuZG93bikpCiAgICAKICAgIH0KICAKICBwcm90ZWluID0gbWV0YWRhdGFbYEZpbGUgYWNjZXNzaW9uYD09c2FtcGxlLCBgRXhwZXJpbWVudCB0YXJnZXRgIF0KICBjZWxsX2xpbmUgPSBtZXRhZGF0YVtgRmlsZSBhY2Nlc3Npb25gPT1zYW1wbGUsIGBCaW9zYW1wbGUgdGVybSBuYW1lYF0KICBuYW1lID0gcGFzdGUocHJvdGVpbiwgY2VsbF9saW5lLCBzYW1wbGUsIHNlcD0iXyIpCiAgCiAgCiAgbWF0cml4Lm5vbl90ZW1wbGF0ZSA8LSByYmluZChtYXRyaXgubm9uX3RlbXBsYXRlLCBjKFRvdGFsLmRlbHRhcy5ub25fdGVtcGxhdGUudXAsIFRvdGFsLmRlbHRhcy5ub25fdGVtcGxhdGUuZG93bikpCiAgCiAgbWF0cml4Lm5vbl90ZW1wbGF0ZS5yb3dfbmFtZXMgPC0gYyhtYXRyaXgubm9uX3RlbXBsYXRlLnJvd19uYW1lcywgbmFtZSkKCgojICB9CiAgCiN9CmBgYAoKCgoKCiMjIyBGYXJtCgpgYGB7cn0KCmRlbHRhLm5vbl90ZW1wbGF0ZS5yb3dzIDwtIGMoKQptYXRyaXgubm9uX3RlbXBsYXRlLnJvd19uYW1lcyA8LSBjKCkKbWF0cml4Lm5vbl90ZW1wbGF0ZSA8LSBjKCkKCmZvciAoc2FtcGxlIGluIHNhbXBsZXMpewogIAogIGlmICggKGxlbmd0aCggbGlzdC5maWxlcygiLi9zY29yZXMvIiwgcGF0dGVybiA9IHNhbXBsZSkpPT0xOTIgKSAmIChtZXRhZGF0YVtgRmlsZSBhY2Nlc3Npb25gPT1zYW1wbGUsIEFzc2VtYmx5XT09ImhnMTkiICkgKSB7CgogICAgUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZSA8LSBwbG90X2VxbF9kaWZmX2Jpbm9taWFsX3RhYmxlKAogICAgICBwYXN0ZSgiLi9zY29yZXMvZXhvbi51cF9wbHVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX3BsdXNfc3RyYW5kLndvRzQuc2NvcmUuIiwgc2FtcGxlLCAiLmJlZC5saXN0Lm91dC5udW0iLCBzZXA9IiIpLAogICAgICBwYXN0ZSgiLi9zY29yZXMvZXhvbi51cF9taW51cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9taW51c19zdHJhbmQud29HNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgICAgIHBhc3RlKCIuL3Njb3Jlcy9leG9uLmRvd25fcGx1cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9wbHVzX3N0cmFuZC53b0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICAgICAgcGFzdGUoIi4vc2NvcmVzL2V4b24uZG93bl9taW51cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9taW51c19zdHJhbmQud29HNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgICAgIHBhc3RlKCIuL3Njb3Jlcy9leG9uLnVwX3BsdXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fcGx1c19zdHJhbmQud0c0LnNjb3JlLiIsIHNhbXBsZSwgIi5iZWQubGlzdC5vdXQubnVtIiwgc2VwPSIiKSwKICAgICAgcGFzdGUoIi4vc2NvcmVzL2V4b24udXBfbWludXMuYmVkLmZpbHRlcmVkLjEwMGJwX2ludHJvbi5pbnRlcnNlY3Rfd2FvLkFsbF9HNC50c3YuY2xlYW5fbWludXNfc3RyYW5kLndHNC5zY29yZS4iLCBzYW1wbGUsICIuYmVkLmxpc3Qub3V0Lm51bSIsIHNlcD0iIiksCiAgICAgIHBhc3RlKCIuL3Njb3Jlcy9leG9uLmRvd25fcGx1cy5iZWQuZmlsdGVyZWQuMTAwYnBfaW50cm9uLmludGVyc2VjdF93YW8uQWxsX0c0LnRzdi5jbGVhbl9wbHVzX3N0cmFuZC53RzQuc2NvcmUuIiwgc2FtcGxlLCAiLmJlZC5saXN0Lm91dC5udW0iLCBzZXA9IiIpLAogICAgICBwYXN0ZSgiLi9zY29yZXMvZXhvbi5kb3duX21pbnVzLmJlZC5maWx0ZXJlZC4xMDBicF9pbnRyb24uaW50ZXJzZWN0X3dhby5BbGxfRzQudHN2LmNsZWFuX21pbnVzX3N0cmFuZC53RzQuc2NvcmUuIiwgc2FtcGxlLCAiLmJlZC5saXN0Lm91dC5udW0iLCBzZXA9IiIpLAogICAgICAxMTA4NzAgKyAxMDk0NjcsCiAgICAgIDEwODYzOCArIDEwNzQzMywKICAgICAgMzU4NyArIDM0MzEsCiAgICAgIDU4MTkgKyA1NDY1LAogICAgICAwLjA1CiAgICApCgogIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGUkcG9zX2ludCA8LSBjdXQoUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZSRQb3NpdGlvbiwgYnJlYWtzID0gMjAwLCBsYWJlbHMgPSBzZXEoLTk5OSwxMDAwLDEwKS0xKQogIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGVfc3RhdHMgPC0gUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZVsgLCAuKEVucnJpY2htZW50PW1lYW4oRW5ycmljaG1lbnQpLCBFbnJyaWNobWVudF9sPW1lYW4oRW5ycmljaG1lbnRfbCksICAgRW5ycmljaG1lbnRfdT1tZWFuKEVucnJpY2htZW50X3UpKSAgLCBieT1jKCAiZXhvbl9wb3MiLCAidHlwZSIsICAicG9zX2ludCIgICkgXQogIAogIAogIFRvdGFsLmRlbHRhcy5ub25fdGVtcGxhdGUudXAgPC0gYygpCiAgVG90YWwuZGVsdGFzLm5vbl90ZW1wbGF0ZS5kb3duIDwtIGMoKQogIAogICAgICBmb3IgKGkgaW4gc2VxKC0yMDAsIDE5MCwgMTApKXsKICAgIAogICAgTy5VcHN0cmVhbSA8LSBPdmVybGFwKAogICAgUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZV9zdGF0c1sgZXhvbl9wb3M9PSJVcHN0cmVhbSIgJiBwb3NfaW50PT1pICYgdHlwZT09IndHNCIsIGMoIkVucnJpY2htZW50X2wiLCAiRW5ycmljaG1lbnRfdSIpXSwKICAgIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGVfc3RhdHNbIGV4b25fcG9zPT0iVXBzdHJlYW0iICYgcG9zX2ludD09aSAmIHR5cGU9PSJ3b0c0IiwgYygiRW5ycmljaG1lbnRfbCIsICJFbnJyaWNobWVudF91IildCiAgICApCiAgICAKICAgIGlmIChpcy5uYShPLlVwc3RyZWFtKSl7CiAgICAgIAogICAgICBPLlVwc3RyZWFtIDwtIDEKICAgIH0KICAgIAogICAgTy5Eb3duc3RyZWFtIDwtIE92ZXJsYXAoCiAgICBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlX3N0YXRzWyBleG9uX3Bvcz09IkRvd25zdHJlYW0iICYgcG9zX2ludD09aSAmIHR5cGU9PSJ3RzQiLCBjKCJFbnJyaWNobWVudF9sIiwgIkVucnJpY2htZW50X3UiKV0sCiAgICBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlX3N0YXRzWyBleG9uX3Bvcz09IkRvd25zdHJlYW0iICYgcG9zX2ludD09aSAmIHR5cGU9PSJ3b0c0IiwgYygiRW5ycmljaG1lbnRfbCIsICJFbnJyaWNobWVudF91IildCiAgICApCiAgICAKICAgIGlmIChpcy5uYShPLkRvd25zdHJlYW0pKXsKICAgICAgCiAgICAgIE8uRG93bnN0cmVhbSA8LSAxCiAgIH0gICAgCiAgICAKICAgIGRlbHRhLnVwIDwtIDAKICAgIAogICAgaWYgKE8uVXBzdHJlYW09PTAgKSB7CiAgICAgIAogICAgICBkZWx0YS51cCA8LSBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlX3N0YXRzWyBleG9uX3Bvcz09IlVwc3RyZWFtIiAmIHBvc19pbnQ9PWkgJiB0eXBlPT0id0c0IiwgIkVucnJpY2htZW50Il0gLSBSQlBfYmlub21pYWxfdGFibGVfbm9uX3RlbXBsYXRlX3N0YXRzWyBleG9uX3Bvcz09IlVwc3RyZWFtIiAmIHBvc19pbnQ9PWkgJiB0eXBlPT0id29HNCIsICJFbnJyaWNobWVudCJdCiAgICAgIAogICAgICAKICAgIH0KICAgICAgCiAgICAgIAogICAgZGVsdGEuZG93biA8LSAwCiAgICAKICAgIGlmIChPLkRvd25zdHJlYW09PTAgKSB7CiAgICAgIAogICAgICBkZWx0YS5kb3duIDwtIFJCUF9iaW5vbWlhbF90YWJsZV9ub25fdGVtcGxhdGVfc3RhdHNbIGV4b25fcG9zPT0iRG93bnN0cmVhbSIgJiBwb3NfaW50PT1pICYgdHlwZT09IndHNCIsICJFbnJyaWNobWVudCJdIC0gUkJQX2Jpbm9taWFsX3RhYmxlX25vbl90ZW1wbGF0ZV9zdGF0c1sgZXhvbl9wb3M9PSJEb3duc3RyZWFtIiAmIHBvc19pbnQ9PWkgJiB0eXBlPT0id29HNCIsICJFbnJyaWNobWVudCJdCiAgICAgIAogICAgICAKICAgIH0KICAgICAgICAKICAgIFRvdGFsLmRlbHRhcy5ub25fdGVtcGxhdGUudXAgPC0gYyhUb3RhbC5kZWx0YXMubm9uX3RlbXBsYXRlLnVwLCBhcy5udW1lcmljKGRlbHRhLnVwKSkKICAgIFRvdGFsLmRlbHRhcy5ub25fdGVtcGxhdGUuZG93biA8LSBjKFRvdGFsLmRlbHRhcy5ub25fdGVtcGxhdGUuZG93biwgYXMubnVtZXJpYyhkZWx0YS5kb3duKSkKICAgIAogICAgfQogIAogIHByb3RlaW4gPSBtZXRhZGF0YVtgRmlsZSBhY2Nlc3Npb25gPT1zYW1wbGUsIGBFeHBlcmltZW50IHRhcmdldGAgXQogIGNlbGxfbGluZSA9IG1ldGFkYXRhW2BGaWxlIGFjY2Vzc2lvbmA9PXNhbXBsZSwgYEJpb3NhbXBsZSB0ZXJtIG5hbWVgXQogIG5hbWUgPSBwYXN0ZShwcm90ZWluLCBjZWxsX2xpbmUsIHNhbXBsZSwgc2VwPSJfIikKICAKICAKICBtYXRyaXgubm9uX3RlbXBsYXRlIDwtIHJiaW5kKG1hdHJpeC5ub25fdGVtcGxhdGUsIGMoVG90YWwuZGVsdGFzLm5vbl90ZW1wbGF0ZS51cCwgVG90YWwuZGVsdGFzLm5vbl90ZW1wbGF0ZS5kb3duKSkKICAKICBtYXRyaXgubm9uX3RlbXBsYXRlLnJvd19uYW1lcyA8LSBjKG1hdHJpeC5ub25fdGVtcGxhdGUucm93X25hbWVzLCBuYW1lKQoKCiAgfQogIAp9CgoKCmBgYAoKCmBgYHtyfQpmaWd1cmU2X3RhYmxlCmBgYAoKCmBgYHtyfQpyb3duYW1lcyhtYXRyaXgubm9uX3RlbXBsYXRlKSA8LSBtYXRyaXgubm9uX3RlbXBsYXRlLnJvd19uYW1lcwpjb2xuYW1lcyhtYXRyaXgubm9uX3RlbXBsYXRlKSAgPC0gYyhwYXN0ZTAoIlVQIiwgIGFzLmNoYXJhY3RlcihzZXEoLTIwMCwxOTAsIDEwKSkgKSwgcGFzdGUwKCJET1dOIiwgIGFzLmNoYXJhY3RlcihzZXEoLTIwMCwxOTAsIDEwKSkgKSkKd3JpdGUudGFibGUoRFQubm9uX3RlbXBsYXRlLCBmaWxlID0gIi4vbm9uX3RlbXBsYXRlLlJCUC5tYXRyaXgiLCByb3cubmFtZXM9VCwgY29sLm5hbWVzPVQsIHF1b3RlPUYpCmBgYAoKCgpgYGB7cn0KZGF0YV90YWJsZS5ub25fdGVtcGxhdGUgPC0gZnJlYWQoIi4vUkJQcy90YWJsZXMvbm9uX3RlbXBsYXRlLlJCUC5tYXRyaXgiKQoKbWF0cml4Lm5vbl90ZW1wbGF0ZSA8LSBhcy5tYXRyaXgoZGF0YV90YWJsZS5ub25fdGVtcGxhdGVbLCBjKHBhc3RlMCgiVVAiLCAgYXMuY2hhcmFjdGVyKHNlcSgtMjAwLDE5MCwgMTApKSApLCBwYXN0ZTAoIkRPV04iLCAgYXMuY2hhcmFjdGVyKHNlcSgtMjAwLDE5MCwgMTApKSApKV0pCnJvd25hbWVzKG1hdHJpeC5ub25fdGVtcGxhdGUpIDwtIGRhdGFfdGFibGUubm9uX3RlbXBsYXRlJFYxCmBgYAoKCgpgYGB7cn0KCm1hdHJpeC5ub25fdGVtcGxhdGVbd2hpY2goIWlzLmZpbml0ZShtYXRyaXgubm9uX3RlbXBsYXRlKSldIDwtIDAKCm1hdHJpeC5ub25fdGVtcGxhdGUuZmlsdGVyIDwtIG1hdHJpeC5ub25fdGVtcGxhdGVbIHJvd1N1bXMoYWJzKG1hdHJpeC5ub25fdGVtcGxhdGUpKT4zMCwgXQoKZGltKG1hdHJpeC5ub25fdGVtcGxhdGUpCmRpbShtYXRyaXgubm9uX3RlbXBsYXRlLmZpbHRlcikKCmBgYAoKCgoKCmBgYHtyfQp0ZXN0ID0gbWF0cml4KHJub3JtKDIwMCksIDIwLCAxMCkKdGVzdFsxOjEwLCBzZXEoMSwgMTAsIDIpXSA9IHRlc3RbMToxMCwgc2VxKDEsIDEwLCAyKV0gKyAzCnRlc3RbMTE6MjAsIHNlcSgyLCAxMCwgMildID0gdGVzdFsxMToyMCwgc2VxKDIsIDEwLCAyKV0gKyAyCnRlc3RbMTU6MjAsIHNlcSgyLCAxMCwgMildID0gdGVzdFsxNToyMCwgc2VxKDIsIDEwLCAyKV0gKyA0CmNvbG5hbWVzKHRlc3QpID0gcGFzdGUoIlRlc3QiLCAxOjEwLCBzZXAgPSAiIikKcm93bmFtZXModGVzdCkgPSBwYXN0ZSgiTmFtZSIsIDE6MjAsIHNlcCA9ICIiKQoKcGFsZXR0ZUxlbmd0aCA8LSA1MApteUNvbG9yIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkocGFsZXR0ZUxlbmd0aCkKIyBsZW5ndGgoYnJlYWtzKSA9PSBsZW5ndGgocGFsZXR0ZUxlbmd0aCkgKyAxCiMgdXNlIGZsb29yIGFuZCBjZWlsaW5nIHRvIGRlYWwgd2l0aCBldmVuL29kZCBsZW5ndGggcGFsbGV0dGVsZW5ndGhzCm15QnJlYWtzIDwtIGMoc2VxKG1pbih0ZXN0KSwgMCwgbGVuZ3RoLm91dD1jZWlsaW5nKHBhbGV0dGVMZW5ndGgvMikgKyAxKSwgCiAgICAgICAgICAgICAgc2VxKG1heCh0ZXN0KS9wYWxldHRlTGVuZ3RoLCBtYXgodGVzdCksIGxlbmd0aC5vdXQ9Zmxvb3IocGFsZXR0ZUxlbmd0aC8yKSkpCgpgYGAKCmBgYHtyfQpiazEgPC0gYyhzZXEoLTYsMC45LGJ5PTAuMDAxKSwwLjk5OSkKYmsyIDwtIGMoMS4wMDEsc2VxKDEuMSw2LGJ5PTAuMSkpCmJrIDwtIGMoYmsxLGJrMikgICNjb21iaW5lIHRoZSBicmVhayBsaW1pdHMgZm9yIHB1cnBvc2Ugb2YgZ3JhcGhpbmcKCm15X3BhbGV0dGUgPC0gYyhjb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IGMoImRhcmtibHVlIiwgImxpZ2h0Ymx1ZSIpKShuID0gbGVuZ3RoKGJrMSktMSksCiAgICAgICAgICAgICAgImdyYXkzOCIsICJncmF5MzgiLAogICAgICAgICAgICAgIGMoY29sb3JSYW1wUGFsZXR0ZShjb2xvcnMgPSBjKCJkYXJrcmVkIiwgInRvbWF0bzEiKSkobiA9IGxlbmd0aChiazIpLTEpKSkKCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CgpteS5icmVha3MgPC0gYyhzZXEoLTYsIC0wLjAwMSwgYnk9MC4wMDEpLAogICAgICAgICAgICAgICBzZXEoMC4wMDEsIDYsIGJ5PTAuMDAxKSkgCm15LmNvbG9ycyA8LSBjKGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYygiZGFya2JsdWUiLCAibGlnaHRibHVlIiwgImFudGlxdWV3aGl0ZSIpKShsZW5ndGgobXkuYnJlYWtzKS8yKSwKICAgICAgICAgICAgICAgY29sb3JSYW1wUGFsZXR0ZShjb2xvcnMgPSBjKCJiaXNxdWUiLCAicmVkIiwgImZpcmVicmljayIpKShsZW5ndGgobXkuYnJlYWtzKS8yKSkKCgpSQlBfaGVhdG1hcC5ub25fdGVtcGxhdGUgPC0gcGhlYXRtYXA6OnBoZWF0bWFwKG1hdHJpeC5ub25fdGVtcGxhdGUsIGZvbnRzaXplID0gNCwgICBjdXRyZWVfcm93cyA9IDgsIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRCIsIGNsdXN0ZXJfY29scz1GLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IG15LmNvbG9ycywgYnJlYWtzID0gbXkuYnJlYWtzLCBzY2FsZSA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzPUYsIHNob3dfY29sbmFtZXMgPSBGKQpgYGAKCgpgYGB7cn0KbWF0cml4Lm5vbl90ZW1wbGF0ZVsiWkMzSDjiiJJodW1hbl9LNTYyX0VOQ0ZGMjA3VVVHIixdClZpZXcobWF0cml4Lm5vbl90ZW1wbGF0ZSkKVmlldyhkYXRhX3RhYmxlLm5vbl90ZW1wbGF0ZSkKCmRhdGFfdGFibGUubm9uX3RlbXBsYXRlW1YxPT0iWkMzSDjiiJJodW1hbl9LNTYyX0VOQ0ZGMjA3VVVHIiwgXQpgYGAKCgoKCmBgYHtyfQpkYXRhX3RhYmxlLnRlbXBsYXRlIDwtIGZyZWFkKCIuL1JCUHMvdGFibGVzL3RlbXBsYXRlLlJCUC5tYXRyaXgiKQoKbWF0cml4LnRlbXBsYXRlIDwtIGFzLm1hdHJpeChkYXRhX3RhYmxlLnRlbXBsYXRlWywgYyhwYXN0ZTAoIlVQIiwgIGFzLmNoYXJhY3RlcihzZXEoLTIwMCwxOTAsIDEwKSkgKSwgcGFzdGUwKCJET1dOIiwgIGFzLmNoYXJhY3RlcihzZXEoLTIwMCwxOTAsIDEwKSkgKSldKQpyb3duYW1lcyhtYXRyaXgudGVtcGxhdGUpIDwtIGRhdGFfdGFibGUudGVtcGxhdGUkVjEKYGBgCgoKCmBgYHtyfQoKbWF0cml4LnRlbXBsYXRlW3doaWNoKCFpcy5maW5pdGUobWF0cml4LnRlbXBsYXRlKSldIDwtIDAKCm1hdHJpeC50ZW1wbGF0ZS5maWx0ZXIgPC0gbWF0cml4LnRlbXBsYXRlWyByb3dTdW1zKGFicyhtYXRyaXgudGVtcGxhdGUpKT4xLCBdCgoKCgpkaW0obWF0cml4LnRlbXBsYXRlLmZpbHRlcikKI1ZpZXcobWF0cml4LnRlbXBsYXRlLmZpbHRlcikKYGBgCgpgYGB7cn0KCmMoYyg4MToxMTAgKSwgKDEzMToxNjApKQoKbWF0cml4LnRvdGFsWywgYyggYygxOjMwKSwgYyg1MToxMTApLCAoMTMxOjE2MCkgKSAgICBdCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CgoKUkJQX2hlYXRtYXAudGVtcGxhdGUgPC0gcGhlYXRtYXA6OnBoZWF0bWFwKG1hdHJpeC50ZW1wbGF0ZSwgZm9udHNpemUgPSA0LCAgIGN1dHJlZV9yb3dzID0gOCwgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EIiwgY2x1c3Rlcl9jb2xzPUYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IG15LmNvbG9ycywgYnJlYWtzID0gbXkuYnJlYWtzLCBzY2FsZSA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93bmFtZXM9Riwgc2hvd19jb2xuYW1lcyA9IEYpCmBgYAoKCgoKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0KbGlicmFyeShnZ2FsbHV2aWFsKQpsaWJyYXJ5KHBseXIpCgpjbHVzdGVyaW5nLm5vbl90ZW1wbGF0ZSA8LSBoY2x1c3QoZGlzdChtYXRyaXgubm9uX3RlbXBsYXRlKSwgbWV0aG9kID0gIndhcmQuRCIpCmNsdXN0ZXJzLm5vbl90ZW1wbGF0ZSA8LSBjdXRyZWUoY2x1c3RlcmluZy5ub25fdGVtcGxhdGUsIGs9OCkKCgoKCmNsdXN0ZXJpbmcudGVtcGxhdGUgPC0gaGNsdXN0KGRpc3QobWF0cml4LnRlbXBsYXRlKSwgbWV0aG9kID0gIndhcmQuRCIpCmNsdXN0ZXJzLnRlbXBsYXRlIDwtIGN1dHJlZShjbHVzdGVyaW5nLnRlbXBsYXRlLCBrPTgpCgoKY2x1c3RlcmluZy50b3RhbCA8LSAgYXMuZGF0YS5mcmFtZShjYmluZChjbHVzdGVycy5ub25fdGVtcGxhdGUsIGNsdXN0ZXJzLnRlbXBsYXRlID0gY2x1c3RlcnMudGVtcGxhdGVbbmFtZXMoY2x1c3RlcnMubm9uX3RlbXBsYXRlKV0pKQoKCmNsdXN0ZXJpbmcudG90YWwkY2x1c3RlcnMubm9uX3RlbXBsYXRlIDwtIG1hcHZhbHVlcyhjbHVzdGVyaW5nLnRvdGFsJGNsdXN0ZXJzLm5vbl90ZW1wbGF0ZSAsIAogICAgICAgICAgZnJvbSA9MTo4LAogICAgICAgICAgdG8gPSBjKCJuczIiLCAiaUIyIiwgImlCMSIsICJpQnNVIiwgIm5zMSIsICJpZUIyIiwgImllQjEiLCAiaUJzRCIpKQoKCmNsdXN0ZXJpbmcudG90YWwkY2x1c3RlcnMudGVtcGxhdGUgPC0gbWFwdmFsdWVzKGNsdXN0ZXJpbmcudG90YWwkY2x1c3RlcnMudGVtcGxhdGUgLCAKICAgICAgICAgIGZyb20gPTE6OCwKICAgICAgICAgIHRvID0gYygibnMxIiwgIm5zMiIsICJpZUIyIiwgImlCMSIsICJpQjIiLCAiaUJzVSIsICJpQnNEIiwgImllQjEiKSkKCgpjbHVzdGVyaW5nLnRvdGFsJHNhbXBsZSA8LSByb3duYW1lcyhjbHVzdGVyaW5nLnRvdGFsKQoKY2x1c3RlcmluZy50b3RhbCA8LSBkYXRhLnRhYmxlKGNsdXN0ZXJpbmcudG90YWwpCgoKY2x1c3RlcmluZy50b3RhbC5zdGF0cyA8LSBjbHVzdGVyaW5nLnRvdGFsWyAsIC5OICwgYnkgPWMoImNsdXN0ZXJzLm5vbl90ZW1wbGF0ZSIsICJjbHVzdGVycy50ZW1wbGF0ZSIpXQoKZ2dwbG90KGNsdXN0ZXJpbmcudG90YWwuc3RhdHMsIGFlcyh5PU4sIGF4aXMxPWNsdXN0ZXJzLm5vbl90ZW1wbGF0ZSwgYXhpczI9Y2x1c3RlcnMudGVtcGxhdGUpKSArCiAgZ2VvbV9hbGx1dml1bSggd2lkdGggPSAxLzEyKSArCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS8xMiwgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9sYWJlbChzdGF0ID0gInN0cmF0dW0iLCBsYWJlbC5zdHJhdGEgPSBUUlVFKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJjbHVzdGVycy5ub25fdGVtcGxhdGUiLCAiY2x1c3RlcnMudGVtcGxhdGUiKSwgZXhwYW5kID0gYyguMDUsIC4wNSkpCgpgYGAKCgpgYGB7ciwgIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0KZ2dwbG90KGNsdXN0ZXJpbmcudG90YWwuc3RhdHMsIGFlcyh5PU4sIGF4aXMxPWNsdXN0ZXJzLm5vbl90ZW1wbGF0ZSwgYXhpczI9Y2x1c3RlcnMudGVtcGxhdGUpKSArCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbD1jbHVzdGVycy5ub25fdGVtcGxhdGU9PSJpZUIxIiksIHdpZHRoID0gMS8xMikgKwogIGdlb21fc3RyYXR1bSh3aWR0aCA9IDEvMTIsIGZpbGwgPSAiYmxhY2siLCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fbGFiZWwoc3RhdCA9ICJzdHJhdHVtIiwgbGFiZWwuc3RyYXRhID0gVFJVRSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiY2x1c3RlcnMubm9uX3RlbXBsYXRlIiwgImNsdXN0ZXJzLnRlbXBsYXRlIiksIGV4cGFuZCA9IGMoLjA1LCAuMDUpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImdyZXkiLCAiZmlyZWJyaWNrIikpCmBgYAoKCgpgYGB7cn0KZ2dwbG90KGFzLmRhdGEuZnJhbWUoVUNCQWRtaXNzaW9ucyksCiAgICAgICBhZXMoeSA9IEZyZXEsIGF4aXMxID0gR2VuZGVyLCBheGlzMiA9IERlcHQpKSArCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbCA9IEFkbWl0KSwgd2lkdGggPSAxLzEyKSArCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS8xMiwgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9sYWJlbChzdGF0ID0gInN0cmF0dW0iLCBsYWJlbC5zdHJhdGEgPSBUUlVFKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJHZW5kZXIiLCAiRGVwdCIpLCBleHBhbmQgPSBjKC4wNSwgLjA1KSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAiU2V0MSIpIApgYGAKCgoKYGBge3IsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTIwfQoKbWF0cml4LnRvdGFsIDwtIGNiaW5kKG1hdHJpeC5ub25fdGVtcGxhdGUsIG1hdHJpeC50ZW1wbGF0ZSkKCm1hdHJpeC50b3RhbC50cmltIDwtIG1hdHJpeC50b3RhbFssIGMoIGMoMTozMCksIGMoNTE6MTEwKSwgKDEzMToxNjApICkgICAgXQoKCm50X3QuY29sbmFtZXMgPC0gIGMocGFzdGUwKCJudFVQIiwgIGFzLmNoYXJhY3RlcihzZXEoLTIwMCwxOTAsIDEwKSkgKSwgcGFzdGUwKCJudERPV04iLCAgYXMuY2hhcmFjdGVyKHNlcSgtMjAwLDE5MCwgMTApKSApLCAgYyhwYXN0ZTAoInRVUCIsICBhcy5jaGFyYWN0ZXIoc2VxKC0yMDAsMTkwLCAxMCkpICksIHBhc3RlMCgidERPV04iLCAgYXMuY2hhcmFjdGVyKHNlcSgtMjAwLDE5MCwgMTApKSApKSApCgoKCmNvbG5hbWVzKG1hdHJpeC50b3RhbCkgPC0gbnRfdC5jb2xuYW1lcwoKTmV3X2ZpZy4xIDwtIHBoZWF0bWFwOjpwaGVhdG1hcChtYXRyaXgudG90YWwudHJpbSwgZm9udHNpemUgPSA0LCAgIGN1dHJlZV9yb3dzID0gMTAsIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRCIsIGNsdXN0ZXJfY29scz1GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBteS5jb2xvcnMsIGJyZWFrcyA9IG15LmJyZWFrcywgc2NhbGUgPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzPUYsIHNob3dfY29sbmFtZXMgPSBGLCBsZWdlbmQgPSBUKQoKYGBgCgoKCmBgYHtyfQoKaGNfcm93cyA8LSBoY2x1c3QoZGlzdChtYXRyaXgudG90YWwudHJpbSksIG1ldGhvZCA9ICJ3YXJkLkQiKQoKUkJQX2NsdXN0ZXJzIDwtICBjdXRyZWUoaGNfcm93cywgaz0xMCkKCgpSQlBfY2x1c3RlcnMudGFibGUgPC0gZGF0YS50YWJsZShjYmluZChuYW1lcyhSQlBfY2x1c3RlcnMpLCBhcy5udW1lcmljKFJCUF9jbHVzdGVycykpKQoKY29sbmFtZXMoUkJQX2NsdXN0ZXJzLnRhYmxlKSA8LSBjKCJJRCIsICJjbHVzdGVyIikKClJCUF9jbHVzdGVycy50YWJsZSA8LSBkYXRhLnRhYmxlKFJCUF9jbHVzdGVycy50YWJsZSkKCgoKCgoKUkJQX2NsdXN0ZXJzLnRhYmxlIDwtIGNiaW5kKFJCUF9jbHVzdGVycy50YWJsZSwgc3RyX3NwbGl0X2ZpeGVkKFJCUF9jbHVzdGVycy50YWJsZSRJRCwgIl8iLCAzKSkKCgpSQlBfY2x1c3RlcnMudGFibGUgPC0gY2JpbmQoUkJQX2NsdXN0ZXJzLnRhYmxlLCBzdHJfc3BsaXRfZml4ZWQoUkJQX2NsdXN0ZXJzLnRhYmxlJFYxLCAiLSIsIDIpKQoKUkJQX2NsdXN0ZXJzLnRhYmxlIDwtIFJCUF9jbHVzdGVycy50YWJsZVssIGMoMSwyLDQsNSw2LDcpXQoKY29sbmFtZXMoUkJQX2NsdXN0ZXJzLnRhYmxlKSA8LSBjKCJJRCIsICJjbHVzdGVyIiwgIkNlbGwiLCAiRmlsZSIsICJHZW5lIiwgIk9yZ2FuaXNtIikKCgoKYGBgCgoKIyMjIyMjIyMjCgoKCmBgYHtyfQoKCgpSQlBfaGVhdG1hcC50b3RhbCA8LSBwaGVhdG1hcDo6cGhlYXRtYXAobWF0cml4LnRvdGFsLnRyaW0sIGZvbnRzaXplID0gNCwgICBjdXRyZWVfcm93cyA9IDEwLCBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQiLCBjbHVzdGVyX2NvbHM9RiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gbXkuY29sb3JzLCBicmVha3MgPSBteS5icmVha3MsIHNjYWxlID0gIm5vbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19yb3duYW1lcz1ULCBzaG93X2NvbG5hbWVzID0gRikKCmBgYAoKCgoKCmBgYHtyfQpoYSA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gYW5ubzEsIGFubm9fZnVuID0gYW5ubzIsIC4uLikKSGVhdG1hcChtYXRyaXgudG90YWwudHJpbSwgdG9wX2Fubm90YXRpb24gPSBoYSkKYGBgCgoKIyMjIyMjCgoKCgoKIyMjIyMjIwoKIyBSTkEtc2VxIGFuYWx5c2lzCgojIyMjIyMjCgoKCgoKCmBgYHtyfQoKcmVwbGFjZV9wX3ZhbHVlIDwtIGZ1bmN0aW9uKGNoaXNxX3RhYmxlKXsKICAKICAKICBucm93cyA8LSBucm93KGNoaXNxX3RhYmxlKQogIHByaW50KGNoaXNxX3RhYmxlKQogIAogIGZvciAoaSBpbiAxOm5yb3dzKSB7CiAgCgogIAogIGNvblRhYmxlIDwtIG1hdHJpeChucm93ID0gMiwgYyhjaGlzcV90YWJsZVtpLCBlcWxfbm90RzRdICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hpc3FfdGFibGVbaSwgZGlmZl9ub3RHNF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaXNxX3RhYmxlW2kgLGVxbF9HNF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaXNxX3RhYmxlW2ksIGRpZmZfRzRdICkpCiAgCiAgCiAgcmVzIDwtIGNoaXNxLnRlc3QoY29uVGFibGUpCiAgY2hpc3FfdGFibGVbaSwgcCA6PSAgcmVzJHAudmFsdWVdCiAgY2hpc3FfdGFibGVbaSwgY2hpc3EgOj0gIGFzLm51bWVyaWMocmVzJHN0YXRpc3RpYyldCiAgY2hpc3FfdGFibGVbaSwgcC5hZGogOj0gIHJlcyRwLnZhbHVlKm5yb3dzXQogIAogIGkgPSBpICsgMQogIAogIH0KfQoKCgpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKbGlicmFyeSgiZ2dyZXBlbCIpCgpiaW5vbWlhbF92dWxjYW5vIDwtIGZ1bmN0aW9uKGNoaXNxX3RhYmxlKXsKCiAgcCA8LSBnZ3Bsb3QoKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSBjaGlzcV90YWJsZSwgYWVzKCBsb2dPUiwgLWxvZyhwLmFkaikgICksIGNvbG91cj0iZ3JleSIsIGFscGhhPTAuNSAgKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSBjaGlzcV90YWJsZVtwLmFkajwwLjA1XSwgYWVzKCBsb2dPUiwgLWxvZyhwLmFkaikgKSAsICBjb2xvdXI9InJlZCIsIGFscGhhPTAuOCAgICkgKwogIAogICAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBjaGlzcV90YWJsZVtwLmFkajwwLjA1ICwgXSwKICAgICAgICAgICAgICAgICAgICBjb2xvdXI9ImJsYWNrIiwgYWVzKCBsb2dPUiwgLWxvZyhwLmFkaiksCiAgICAgICAgICAgICAgICAgICAgI251ZGdlX3kgICAgICA9IDMsCiAgICAgICAgICAgICAgICAgICAgI2RpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICAgICAjYW5nbGUgICAgICAgID0gOTAsCiAgICAgICAgICAgICAgICAgICAgI3ZqdXN0ICAgICAgICA9IDEsCiAgICAgICAgICAgICAgICAgICAgI3NlZ21lbnQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAjbGFiZWwuc2l6ZSA9IDAuMDUsCiAgICAgICAgICAgICAgICAgICAgbGFiZWw9Y2hpc3FfdGFibGVbcC5hZGo8MC4wNSAsIG11dF0pKSAgICsKICAgIAogICAgdGhlbWVfYncoKQogIAogIHJldHVybihwKQoKCn0KCgoKYGBgCgoKCmBgYHtyfQp0ZW1wbGF0ZV9ub25fdGVtcGxhdGUuY2hpc3EgPC0gIGZyZWFkKCIuL3NoUk5BX1JCUC9UT1RBTC5jaGlzcXVhcmVkLnR4dCIpCgpub25fdGVtcGxhdGUuY2hpc3EgPC0gIGZyZWFkKCIuL3NoUk5BX1JCUC9Ob25fdGVtcGxhdGUuY2hpc3F1YXJlZC50eHQiKQp0ZW1wbGF0ZS5jaGlzcSA8LSAgZnJlYWQoIi4vc2hSTkFfUkJQL1RlbXBsYXRlLmNoaXNxdWFyZWQudHh0IikKCm5vbl90ZW1wbGF0ZV91cHN0cmVhbS5jaGlzcSA8LSAgZnJlYWQoIi4vc2hSTkFfUkJQL05vbl90ZW1wbGF0ZV91cHN0cmVhbS5jaGlzcXVhcmVkLnR4dCIpCm5vbl90ZW1wbGF0ZV9kb3duc3RyZWFtLmNoaXNxIDwtICBmcmVhZCgiLi9zaFJOQV9SQlAvTm9uX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hpc3F1YXJlZC50eHQiKQp0ZW1wbGF0ZV91cHN0cmVhbS5jaGlzcSA8LSAgZnJlYWQoIi4vc2hSTkFfUkJQL1RlbXBsYXRlX3Vwc3RyZWFtLmNoaXNxdWFyZWQudHh0IikKdGVtcGxhdGVfZG93bnN0cmVhbS5jaGlzcSA8LSAgZnJlYWQoIi4vc2hSTkFfUkJQL1RlbXBsYXRlX2Rvd25zdHJlYW0uY2hpc3F1YXJlZC50eHQiKQoKCnJlcGxhY2VfcF92YWx1ZSh0ZW1wbGF0ZV9ub25fdGVtcGxhdGUuY2hpc3EpCnJlcGxhY2VfcF92YWx1ZShub25fdGVtcGxhdGUuY2hpc3EpCnJlcGxhY2VfcF92YWx1ZSh0ZW1wbGF0ZS5jaGlzcSkKCnJlcGxhY2VfcF92YWx1ZShub25fdGVtcGxhdGVfdXBzdHJlYW0uY2hpc3EpCnJlcGxhY2VfcF92YWx1ZShub25fdGVtcGxhdGVfZG93bnN0cmVhbS5jaGlzcSkKcmVwbGFjZV9wX3ZhbHVlKHRlbXBsYXRlX3Vwc3RyZWFtLmNoaXNxKQpyZXBsYWNlX3BfdmFsdWUodGVtcGxhdGVfZG93bnN0cmVhbS5jaGlzcSkKYGBgCgoKCgpgYGB7cn0KdGVtcGxhdGVfbm9uX3RlbXBsYXRlLmNoaXNxIDwtIGNiaW5kKHRlbXBsYXRlX25vbl90ZW1wbGF0ZS5jaGlzcSwgIHN0cl9zcGxpdF9maXhlZCh0ZW1wbGF0ZV9ub25fdGVtcGxhdGUuY2hpc3EkbXV0LCAiXyIsIDIpKQpjb2xuYW1lcyh0ZW1wbGF0ZV9ub25fdGVtcGxhdGUuY2hpc3EpIDwtIGMoIm11dCIsICJjb250cm9sIiwgImVxbF9ub3RHNCIsICJlcWxfRzQiLCAiZGlmZl9ub3RHNCIsICJkaWZmX0c0IiwgImxvZ09SIiwgImNoaXNxIiwgInAiLCAicC5hZGoiLCAiQ2VsbCIsICJHZW5lIiApIAoKbm9uX3RlbXBsYXRlLmNoaXNxIDwtIGNiaW5kKG5vbl90ZW1wbGF0ZS5jaGlzcSwgIHN0cl9zcGxpdF9maXhlZChub25fdGVtcGxhdGUuY2hpc3EkbXV0LCAiXyIsIDIpKQpjb2xuYW1lcyhub25fdGVtcGxhdGUuY2hpc3EpIDwtIGMoIm11dCIsICJjb250cm9sIiwgImVxbF9ub3RHNCIsICJlcWxfRzQiLCAiZGlmZl9ub3RHNCIsICJkaWZmX0c0IiwgImxvZ09SIiwgImNoaXNxIiwgInAiLCAicC5hZGoiLCAiQ2VsbCIsICJHZW5lIiApIAoKdGVtcGxhdGUuY2hpc3EgPC0gY2JpbmQodGVtcGxhdGUuY2hpc3EsICBzdHJfc3BsaXRfZml4ZWQodGVtcGxhdGUuY2hpc3EkbXV0LCAiXyIsIDIpKQpjb2xuYW1lcyh0ZW1wbGF0ZS5jaGlzcSkgPC0gYygibXV0IiwgImNvbnRyb2wiLCAiZXFsX25vdEc0IiwgImVxbF9HNCIsICJkaWZmX25vdEc0IiwgImRpZmZfRzQiLCAibG9nT1IiLCAiY2hpc3EiLCAicCIsICJwLmFkaiIsICJDZWxsIiwgIkdlbmUiICkgCgoKCgpSQlBfY2x1c3RlcnNfdG90YWwuY2hzcSA8LW1lcmdlKFJCUF9jbHVzdGVycy50YWJsZSwgdGVtcGxhdGVfbm9uX3RlbXBsYXRlLmNoaXNxLCBieT1jKCJDZWxsIiwgIkdlbmUiKSwgYWxsLng9VFJVRSkKClJCUF9jbHVzdGVyc19ub25fdGVtcGxhdGUuY2hzcSA8LW1lcmdlKFJCUF9jbHVzdGVycy50YWJsZSwgbm9uX3RlbXBsYXRlLmNoaXNxLCBieT1jKCJDZWxsIiwgIkdlbmUiKSwgYWxsLng9VFJVRSkKClJCUF9jbHVzdGVyc190ZW1wbGF0ZS5jaHNxIDwtbWVyZ2UoUkJQX2NsdXN0ZXJzLnRhYmxlLCB0ZW1wbGF0ZS5jaGlzcSwgYnk9YygiQ2VsbCIsICJHZW5lIiksIGFsbC54PVRSVUUpCgoKUkJQX2NsdXN0ZXJzX3RvdGFsLmNoc3FbICxvcmllbnRhdGlvbjo9IkJvdGgiXQpSQlBfY2x1c3RlcnNfbm9uX3RlbXBsYXRlLmNoc3FbICxvcmllbnRhdGlvbjo9Ik5vbl90ZW1wbGF0ZSJdClJCUF9jbHVzdGVyc190ZW1wbGF0ZS5jaHNxWyAsb3JpZW50YXRpb246PSJUZW1wbGF0ZSJdCgpSQlBfY2x1c3RlcnNfQUxMLmNoc3EgPC0gcmJpbmQoUkJQX2NsdXN0ZXJzX3RvdGFsLmNoc3EsIFJCUF9jbHVzdGVyc19ub25fdGVtcGxhdGUuY2hzcSwgUkJQX2NsdXN0ZXJzX3RlbXBsYXRlLmNoc3EpCgoKcm93Lm9yZGVyIDwtIFJCUF9oZWF0bWFwLnRvdGFsJHRyZWVfcm93JG9yZGVyIAoKUkJQX2NsdXN0ZXJzX0FMTC5jaHNxJElEIDwtIGZhY3RvcihSQlBfY2x1c3RlcnNfQUxMLmNoc3EkSUQsIGxldmVscz1yZXYoUkJQX2NsdXN0ZXJzLnRhYmxlW3Jvdy5vcmRlciwgXSRJRCkgKQoKCiAKCgoKYGBgCgoKCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01MH0KCnBvcyA8LSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjMsIHNlZWQgPSAyKQoKClJCUF9jbHVzdGVyc19BTEwuY2hzcVsgIHAuYWRqPjAuMDUgLGNvbG91cjo9Im5vbiBzaWduaWZpY2FudCIgXQpSQlBfY2x1c3RlcnNfQUxMLmNoc3FbICBwLmFkajw9MC4wNSAmICBDZWxsPT0iSGVwRzIiLCBjb2xvdXI6PSJIZXBHMiIgXQpSQlBfY2x1c3RlcnNfQUxMLmNoc3FbICBwLmFkajw9MC4wNSAgJiBDZWxsPT0iSzU2MiIsIGNvbG91cjo9Iks1NjIiIF0KCmZpbHRlcmVkX2ZhY3RvcnMgPC0gUkJQX2NsdXN0ZXJzX0FMTC5jaHNxWyBwLmFkajw9MC4wNSAsIC4oLk4pICwgYnk9YygiR2VuZSIsICJDZWxsIiwgImNsdXN0ZXIiLCAib3JpZW50YXRpb24iICldW04+PTIsIHBhc3RlMChHZW5lLCBDZWxsLCBjbHVzdGVyLCBvcmllbnRhdGlvbiApIF0KCiAgCk5ld19maWcuMiA8LSAgICBnZ3Bsb3QoUkJQX2NsdXN0ZXJzX0FMTC5jaHNxKSArCiAgZ2VvbV9qaXR0ZXIoYWVzKHg9SUQsIHk9bG9nT1IsIGNvbG91cj1jb2xvdXIgKSApICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9IHJldihSQlBfY2x1c3RlcnMudGFibGVbcm93Lm9yZGVyLCBdJGNsdXN0ZXIpKSArCiAgZmFjZXRfZ3JpZCggLiB+IG9yaWVudGF0aW9uICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZm9yZXN0Z3JlZW4iLCAicHVycGxlIiwgImdyZXkiKSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1SQlBfY2x1c3RlcnNfQUxMLmNoc3FbIHAuYWRqPD0wLjA1ICYgcGFzdGUwKEdlbmUsIENlbGwsIGNsdXN0ZXIsIG9yaWVudGF0aW9uICkgJWluJSBmaWx0ZXJlZF9mYWN0b3JzICwgXSwgYWVzKHg9SUQsIHk9bG9nT1IsIGxhYmVsPUdlbmUsICksIAogICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IDAuMDEsCiAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvcywKICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC42LCAKICAgICAgICAgICAgICAgICAgIGxhYmVsLnBhZGRpbmc9LjEgKQogIAoKTmV3X2ZpZy4yCmBgYAoKCgpgYGB7cn0KCgoKbm9uX3RlbXBsYXRlX3Vwc3RyZWFtLmNoaXNxIDwtIGNiaW5kKG5vbl90ZW1wbGF0ZV91cHN0cmVhbS5jaGlzcSwgIHN0cl9zcGxpdF9maXhlZChub25fdGVtcGxhdGVfdXBzdHJlYW0uY2hpc3EkbXV0LCAiXyIsIDIpKQpjb2xuYW1lcyhub25fdGVtcGxhdGVfdXBzdHJlYW0uY2hpc3EpIDwtIGMoIm11dCIsICJjb250cm9sIiwgImVxbF9ub3RHNCIsICJlcWxfRzQiLCAiZGlmZl9ub3RHNCIsICJkaWZmX0c0IiwgImxvZ09SIiwgImNoaXNxIiwgInAiLCAicC5hZGoiLCAiQ2VsbCIsICJHZW5lIiApIAoKbm9uX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hpc3EgPC0gY2JpbmQobm9uX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hpc3EsICBzdHJfc3BsaXRfZml4ZWQobm9uX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hpc3EkbXV0LCAiXyIsIDIpKQpjb2xuYW1lcyhub25fdGVtcGxhdGVfZG93bnN0cmVhbS5jaGlzcSkgPC0gYygibXV0IiwgImNvbnRyb2wiLCAiZXFsX25vdEc0IiwgImVxbF9HNCIsICJkaWZmX25vdEc0IiwgImRpZmZfRzQiLCAibG9nT1IiLCAiY2hpc3EiLCAicCIsICJwLmFkaiIsICJDZWxsIiwgIkdlbmUiICkgCgp0ZW1wbGF0ZV91cHN0cmVhbS5jaGlzcSA8LSBjYmluZCh0ZW1wbGF0ZV91cHN0cmVhbS5jaGlzcSwgIHN0cl9zcGxpdF9maXhlZCh0ZW1wbGF0ZV91cHN0cmVhbS5jaGlzcSRtdXQsICJfIiwgMikpCmNvbG5hbWVzKHRlbXBsYXRlX3Vwc3RyZWFtLmNoaXNxKSA8LSBjKCJtdXQiLCAiY29udHJvbCIsICJlcWxfbm90RzQiLCAiZXFsX0c0IiwgImRpZmZfbm90RzQiLCAiZGlmZl9HNCIsICJsb2dPUiIsICJjaGlzcSIsICJwIiwgInAuYWRqIiwgIkNlbGwiLCAiR2VuZSIgKSAKCnRlbXBsYXRlX2Rvd25zdHJlYW0uY2hpc3EgPC0gY2JpbmQodGVtcGxhdGVfZG93bnN0cmVhbS5jaGlzcSwgIHN0cl9zcGxpdF9maXhlZCh0ZW1wbGF0ZV9kb3duc3RyZWFtLmNoaXNxJG11dCwgIl8iLCAyKSkKY29sbmFtZXModGVtcGxhdGVfZG93bnN0cmVhbS5jaGlzcSkgPC0gYygibXV0IiwgImNvbnRyb2wiLCAiZXFsX25vdEc0IiwgImVxbF9HNCIsICJkaWZmX25vdEc0IiwgImRpZmZfRzQiLCAibG9nT1IiLCAiY2hpc3EiLCAicCIsICJwLmFkaiIsICJDZWxsIiwgIkdlbmUiICkKCgoKI1JCUF9jbHVzdGVyc190b3RhbC5jaHNxIDwtbWVyZ2UoUkJQX2NsdXN0ZXJzLnRhYmxlLCB0ZW1wbGF0ZV9ub25fdGVtcGxhdGUuY2hpc3EsIGJ5PWMoIkNlbGwiLCAiR2VuZSIpLCBhbGwueD1UUlVFKQoKUkJQX2NsdXN0ZXJzX25vbl90ZW1wbGF0ZV91cHN0cmVhbS5jaHNxIDwtbWVyZ2UoUkJQX2NsdXN0ZXJzLnRhYmxlLCBub25fdGVtcGxhdGVfdXBzdHJlYW0uY2hpc3EsIGJ5PWMoIkNlbGwiLCAiR2VuZSIpLCBhbGwueD1UUlVFKQpSQlBfY2x1c3RlcnNfbm9uX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hzcSA8LW1lcmdlKFJCUF9jbHVzdGVycy50YWJsZSwgbm9uX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hpc3EsIGJ5PWMoIkNlbGwiLCAiR2VuZSIpLCBhbGwueD1UUlVFKQoKUkJQX2NsdXN0ZXJzX3RlbXBsYXRlX3Vwc3RyZWFtLmNoc3EgPC1tZXJnZShSQlBfY2x1c3RlcnMudGFibGUsIHRlbXBsYXRlX3Vwc3RyZWFtLmNoaXNxLCBieT1jKCJDZWxsIiwgIkdlbmUiKSwgYWxsLng9VFJVRSkKUkJQX2NsdXN0ZXJzX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hzcSA8LW1lcmdlKFJCUF9jbHVzdGVycy50YWJsZSwgdGVtcGxhdGVfZG93bnN0cmVhbS5jaGlzcSwgYnk9YygiQ2VsbCIsICJHZW5lIiksIGFsbC54PVRSVUUpCgoKUkJQX2NsdXN0ZXJzX3RvdGFsLmNoc3FbICxvcmllbnRhdGlvbjo9IlRvdGFsIl0KUkJQX2NsdXN0ZXJzX25vbl90ZW1wbGF0ZV91cHN0cmVhbS5jaHNxWyAsb3JpZW50YXRpb246PSJOb25fdGVtcGxhdGVfdXBzdHJlYW0iXQpSQlBfY2x1c3RlcnNfbm9uX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hzcVsgLG9yaWVudGF0aW9uOj0iTm9uX3RlbXBsYXRlX2Rvd25zdHJlYW0iXQpSQlBfY2x1c3RlcnNfdGVtcGxhdGVfdXBzdHJlYW0uY2hzcVsgLG9yaWVudGF0aW9uOj0iVGVtcGxhdGVfdXBzdHJlYW0iXQpSQlBfY2x1c3RlcnNfdGVtcGxhdGVfZG93bnN0cmVhbS5jaHNxWyAsb3JpZW50YXRpb246PSJUZW1wbGF0ZV9kb3duc3RyZWFtIl0KClJCUF9jbHVzdGVyc19BTEwuY2hzcSA8LSByYmluZChSQlBfY2x1c3RlcnNfdG90YWwuY2hzcSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSQlBfY2x1c3RlcnNfbm9uX3RlbXBsYXRlX3Vwc3RyZWFtLmNoc3EsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSQlBfY2x1c3RlcnNfbm9uX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hzcSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJCUF9jbHVzdGVyc190ZW1wbGF0ZV91cHN0cmVhbS5jaHNxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUkJQX2NsdXN0ZXJzX3RlbXBsYXRlX2Rvd25zdHJlYW0uY2hzcSkKCgpyb3cub3JkZXIgPC0gUkJQX2hlYXRtYXAudG90YWwkdHJlZV9yb3ckb3JkZXIgCgpSQlBfY2x1c3RlcnNfQUxMLmNoc3EkSUQgPC0gZmFjdG9yKFJCUF9jbHVzdGVyc19BTEwuY2hzcSRJRCwgbGV2ZWxzPXJldihSQlBfY2x1c3RlcnMudGFibGVbcm93Lm9yZGVyLCBdJElEKSApCgoKIAoKCmBgYAoKCmBgYHtyfQpodW1hbl9kaWZmWyAhaXMubmEoR2VuZSksIC4oR2VuZSwgbG9nMkZvbGRDaGFuZ2U9LWxvZzJGb2xkQ2hhbmdlLCBwYWRqKSBdCgoKcG9zIDwtIHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IDAuMywgc2VlZCA9IDIpCgoKUkJQX2NsdXN0ZXJzX0FMTC5jaHNxWyAgcC5hZGo+MC4wNSAsY29sb3VyOj0ibm9uIHNpZ25pZmljYW50IiBdClJCUF9jbHVzdGVyc19BTEwuY2hzcVsgIHAuYWRqPD0wLjA1ICYgIENlbGw9PSJIZXBHMiIsIGNvbG91cjo9IkhlcEcyIiBdClJCUF9jbHVzdGVyc19BTEwuY2hzcVsgIHAuYWRqPD0wLjA1ICAmIENlbGw9PSJLNTYyIiwgY29sb3VyOj0iSzU2MiIgXQoKClJCUF9jbHVzdGVyc19BTEwuY2hzcVsgLCBzaWdfS0NsOj0oR2VuZSAlaW4lIGh1bWFuX2RpZmZbcGFkajwwLjA1ICYgIWlzLm5hKEdlbmUpLCBHZW5lXSldCgpmaWx0ZXJlZF9mYWN0b3JzIDwtIFJCUF9jbHVzdGVyc19BTEwuY2hzcVsgcC5hZGo8PTAuMDUgICwgLiguTikgLCBieT1jKCJHZW5lIiwgIkNlbGwiLCAiY2x1c3RlciIsICJvcmllbnRhdGlvbiIgKV1bTj49MiwgcGFzdGUwKEdlbmUsIENlbGwsIGNsdXN0ZXIsIG9yaWVudGF0aW9uICkgXQpSQlBfY2x1c3RlcnNfQUxMLmNoc3Ekb3JpZW50YXRpb24gPC0gZmFjdG9yKFJCUF9jbHVzdGVyc19BTEwuY2hzcSRvcmllbnRhdGlvbiwgbGV2ZWxzID0gYygiVG90YWwiLCAiTm9uX3RlbXBsYXRlX3Vwc3RyZWFtIiwgIk5vbl90ZW1wbGF0ZV9kb3duc3RyZWFtIiwgIlRlbXBsYXRlX3Vwc3RyZWFtIiwgIlRlbXBsYXRlX2Rvd25zdHJlYW0iICAgKSkKCgpgYGAKCgpgYGB7ciwgIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTEyfQpSQlBfY2x1c3RlcnNfQUxMLmNoc3EuS0NsIDwtIG1lcmdlKFJCUF9jbHVzdGVyc19BTEwuY2hzcSwgaHVtYW5fZGlmZlsgIWlzLm5hKEdlbmUpLCAuKEdlbmUsIGxvZzJGb2xkQ2hhbmdlPS1sb2cyRm9sZENoYW5nZSwgcGFkai5LQ2w9cGFkaikgXSwgYnk9IkdlbmUiKQoKZmlsdGVyZWRfZmFjdG9ycy5LQ0wgPC0gdW5pcXVlKFJCUF9jbHVzdGVyc19BTEwuY2hzcS5LQ2xbICAsIC4oLk4pICwgYnk9YygiR2VuZSIsICJDZWxsIiwgImNsdXN0ZXIiLCAib3JpZW50YXRpb24iICldW04+PTIsIEdlbmUgXSkKUkJQX2NsdXN0ZXJzX0FMTC5jaHNxLktDbCRvcmllbnRhdGlvbiA8LSBmYWN0b3IoUkJQX2NsdXN0ZXJzX0FMTC5jaHNxLktDbCRvcmllbnRhdGlvbiwgbGV2ZWxzID0gYygiVG90YWwiLCAiTm9uX3RlbXBsYXRlX3Vwc3RyZWFtIiwgIk5vbl90ZW1wbGF0ZV9kb3duc3RyZWFtIiwgIlRlbXBsYXRlX3Vwc3RyZWFtIiwgIlRlbXBsYXRlX2Rvd25zdHJlYW0iICAgKSkKCmdncGxvdChSQlBfY2x1c3RlcnNfQUxMLmNoc3EuS0NsKSArCiAgZ2VvbV9qaXR0ZXIoYWVzKHg9SUQsIHk9bG9nMkZvbGRDaGFuZ2UsIGNvbG91cj1jb2xvdXIgKSApICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9IHJldihSQlBfY2x1c3RlcnMudGFibGVbcm93Lm9yZGVyLCBdJGNsdXN0ZXIpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJmb3Jlc3RncmVlbiIsICJwdXJwbGUiLCAiZ3JleSIpKSArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPVJCUF9jbHVzdGVyc19BTEwuY2hzcS5LQ2xbICBwYXN0ZTAoR2VuZSwgQ2VsbCwgY2x1c3Rlciwgb3JpZW50YXRpb24gKSAlaW4lIGZpbHRlcmVkX2ZhY3RvcnMuS0NMICwgXSwgYWVzKHg9SUQsIHk9bG9nMkZvbGRDaGFuZ2UsIGxhYmVsPUdlbmUsICksIAogICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IDAuMDEsCiAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvcywKICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC42LCAKICAgICAgICAgICAgICAgICAgIGxhYmVsLnBhZGRpbmc9LjEgKQpgYGAKCgpgYGB7cn0KUkJQX2NsdXN0ZXJzX0FMTC5jaHNxW0ZpbGU9PSJFTkNGRjI0MVNVQyIsXQpgYGAKCgoKYGBge3J9CiBnZ3Bsb3QoUkJQX2NsdXN0ZXJzX0FMTC5jaHNxKSArCiAgZ2VvbV9qaXR0ZXIoYWVzKHg9SUQsIHk9bG9nT1IsIGNvbG91cj1jb2xvdXIgKSApICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9IHJldihSQlBfY2x1c3RlcnMudGFibGVbcm93Lm9yZGVyLCBdJGNsdXN0ZXIpKSArCiAgZmFjZXRfZ3JpZCggLiB+IG9yaWVudGF0aW9uICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZm9yZXN0Z3JlZW4iLCAicHVycGxlIiwgImdyZXkiKSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1SQlBfY2x1c3RlcnNfQUxMLmNoc3FbIHAuYWRqPD0wLjA1ICYgcGFzdGUwKEdlbmUsIENlbGwsIGNsdXN0ZXIsIG9yaWVudGF0aW9uICkgJWluJSBmaWx0ZXJlZF9mYWN0b3JzICwgXSwgYWVzKHg9SUQsIHk9bG9nT1IsIGxhYmVsPUdlbmUsICksIAogICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IDAuMDEsCiAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvcywKICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC42LCAKICAgICAgICAgICAgICAgICAgIGxhYmVsLnBhZGRpbmc9LjEgKQpgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTIwfQoKUkJQX2NsdXN0ZXJzX0FMTC5jaHNxJGNsdXN0ZXIgPC0gZmFjdG9yKFJCUF9jbHVzdGVyc19BTEwuY2hzcSRjbHVzdGVyLCBsZXZlbHM9Yyg0LDgsNSw5LDMsNiwxMCwxLDIsNykpCgpOZXdfZmlnLjIgPC0gZ2dwbG90KFJCUF9jbHVzdGVyc19BTEwuY2hzcSkgKwogIGdlb21faml0dGVyKGFlcyh4PUlELCB5PWxvZ09SLCBjb2xvdXI9Y29sb3VyICkgKSArCiAgY29vcmRfZmxpcCgpICsKCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9IHJldihSQlBfY2x1c3RlcnMudGFibGVbcm93Lm9yZGVyLCBdJGNsdXN0ZXIpKSArCiAgZmFjZXRfZ3JpZCggY2x1c3RlciB+IG9yaWVudGF0aW9uLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZV95Iiwgc3dpdGNoID0gInkiICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZm9yZXN0Z3JlZW4iLCAicHVycGxlIiwgImdyZXkiKSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1SQlBfY2x1c3RlcnNfQUxMLmNoc3FbcC5hZGo8PTAuMDUgJiAgIHBhc3RlMChHZW5lLCBDZWxsLCBjbHVzdGVyLCBvcmllbnRhdGlvbiApICVpbiUgZmlsdGVyZWRfZmFjdG9ycyAsIF0sIGFlcyh4PUlELCB5PWxvZ09SLCBsYWJlbD1HZW5lLCApLCAKCiAgICAgICAgICAgICAgICAgICAgI2ZvcmNlID0gMC41LAogICAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAxLAogICAgICAgICAgICAgICAgICAgICNkaXJlY3Rpb24gPSAieSIsCiAgICAgICAgICAgICAgICAgICAgI2hqdXN0ID0gMCwKICAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgI3NlZ21lbnQuY3VydmF0dXJlID0gLTAuMSwKICAgICAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSAwLjAxLAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIuNSwKICAgICAgICAgICAgICAgICAgICNwb3NpdGlvbiA9IHBvcywKICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC42LCAKICAgICAgICAgICAgICAgICAgIGxhYmVsLnBhZGRpbmc9MC4wMDEsCiAgICAgICAgICAgICAgICAgICBtYXguaXRlcj0xMDAwMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksKQogIAoKTmV3X2ZpZy4yCmBgYAoKCgoKYGBge3IsIGZpZy53aWR0aD0xMywgZmlnLmhlaWdodD0xN30KbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KCJnZ3Bsb3RpZnkiKQoKcGxvdF9ncmlkKCBhcy5ncm9iKE5ld19maWcuMSksIE5ld19maWcuMiwgIHJlbF93aWR0aHMgPSBjKDEsNCkgKQoKYGBgCgoKCmBgYHtyLCBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yMH0KCgoKZ2dwbG90KFJCUF9jbHVzdGVyc19BTEwuY2hzcSkgKwogIGdlb21faml0dGVyKGFlcyh4PUlELCB5PWxvZ09SLCBjb2xvdXI9cC5hZGogPD0gMC4wNSkgKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz0gcmV2KFJCUF9jbHVzdGVycy50YWJsZVtyb3cub3JkZXIsIF0kY2x1c3RlcikpICsKICBmYWNldF9ncmlkKCB+IG9yaWVudGF0aW9uICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JleSIsICJyZWQiKSkgKwogIAoKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGNoaXNxX3RhYmxlW3AuYWRqPDAuMDUgLCBdLAogICAgICAgICAgICAgICAgICAgIGNvbG91cj0iYmxhY2siLCBhZXMoIGxvZ09SLCAtbG9nKHAuYWRqKSwKICAgICAgICAgICAgICAgICAgICBsYWJlbD1jaGlzcV90YWJsZVtwLmFkajwwLjA1ICwgbXV0XSkpICAgKwoKYGBgCgoKCgoKCgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeSggdGlkeXIgKQpsaWJyYXJ5KGdncGxvdDIpCgpkZiA8LSBkYXRhLmZyYW1lKGNsdXN0ZXIgPSBjKHJlcCgiYWFhIiwgOCksIHJlcCgiYmJiIiwgMyksIHJlcCgiY2NjIiwgNCkpLCAKICAgICAgICAgICAgICAgICBib3RoID0gcnVuaWYoMTUsIG1pbiA9IC0xLCBtYXggPSAxKSwKICAgICAgICAgICAgICAgICB0ZW1wbGF0ZSA9IHJ1bmlmKDE1LCBtaW4gPSAtMSwgbWF4ID0gMSksCiAgICAgICAgICAgICAgICAgbm9udGVtcGxhdGUgPSBydW5pZigxNSwgbWluID0gLTEsIG1heCA9IDEpKSAgICAgICAgICAgICAKZGYKCiMgaGVyZSBJIG9yZGVyIHRoZSBlbnRyaWVzIHdpdGhpbiBlYWNoIGNsdXN0ZXIgCiMgYnkgaW5jcmVhc2luZyBvcmRlciBmb3IgdGhlICJib3RoIiBjb2x1bW4KIyBidXQgeW91IHdvdWxkIG9yZGVyIGl0IGJhc2VkIG9uIHRoZSByb3dzIGluIHRoZSBoZWF0bWFwCmRmIDwtIGRmW29yZGVyKGRmJGNsdXN0ZXIsIGRmJGJvdGgpLCBdICAKZGYKCiMgbnVtYmVycyB0aGUgcmVvcmRlcmVkIHJvd3MgYXMgdGhlIHljb29yZAojICJhcy5jaGFyYWN0ZXIiLCBzbyB0aGUgY29vcmRpbmF0ZXMgYXJlIG5vdCB0cmVhdGVkIGFzIGZsb2F0cyBpbiBmYWNldCBncmlkCmRmIDwtIGRmICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgbXV0YXRlKHljb29yZCA9IGFzLmNoYXJhY3Rlcihyb3dfbnVtYmVyKCkpKQpkZgoKIyBub3cgSSBuZWVkIHRvIGdhdGhlciBybmFzZXEgdmFsdWVzIGluIHRoZSBib3RoLCB0ZW1wbGF0ZSBhbmQgbm9udGVtcGxhdGUgY29sdW1ucwpkZiA8LSBnYXRoZXIoZGYsICJzdHJhbmQiLCAicm5hc2VxIiwgYm90aCwgdGVtcGxhdGUsIG5vbnRlbXBsYXRlKQoKZ2dwbG90KGRmLCBhZXMocm5hc2VxLCB5Y29vcmQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKGNsdXN0ZXIgfiBzdHJhbmQsIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlX3kiKQpgYGAKCgoKCgoKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KYmlub21pYWxfdnVsY2Fubyhub25fdGVtcGxhdGUuY2hpc3EpCmBgYAoKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQpiaW5vbWlhbF92dWxjYW5vKHRlbXBsYXRlLmNoaXNxKQpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKYmlub21pYWxfdnVsY2FubyhOb25fdGVtcGxhdGVfZG93bnN0cmVhbS5jaGlzcSkKCgpgYGAKCmBgYHtyfQp0ZW1wbGF0ZV9ub25fdGVtcGxhdGUuY2hpc3FbcC5hZGo8MC4wNV0KYGBgCgo=